elf segment to section mapping mismatch - binaryfiles

I have encountered a pretty mysterious problem after rewriting a ELF binary. I have rewritten a binary using libelf library. Basically I am just replacing some instructions in .text with same number of NOPs. This doesn't change size of any sections, as is evident by readelf output also. However there is some strange mismatch, with respect to original file, in segments to sections mapping after rewriting.
readelf -l output before rewriting:
Elf file type is EXEC (Executable file)
Entry point 0x202a0
There are 8 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x000964 0x10020964 0x10020964 0x00230 0x00230 R 0x4
LOAD 0x010000 0x00020000 0x00020000 0x20000 0x20000 R E 0x10000
LOAD 0x000000 0x10020000 0x10020000 0x00c1c 0x00c1c R 0x10000
LOAD 0x000c20 0x10030c20 0x10030c20 0x00b18 0x010b4 RW 0x10000
NOTE 0x000134 0x10020134 0x10020134 0x0003c 0x0003c R 0x4
TLS 0x000c20 0x10030c20 0x10030c20 0x00478 0x00478 R 0x8
GNU_EH_FRAME 0x000b94 0x10020b94 0x10020b94 0x00014 0x00014 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10
Section to Segment mapping:
Segment Sections...
00 .ARM.exidx
01 .init .text .fini
02 .note.NaCl.ABI.arm .note.gnu.build-id .rodata .ARM.extab .ARM.exidx
.eh_frame_hdr .eh_frame
03 .tdata .init_array .fini_array .jcr .got .data .bss
04 .note.NaCl.ABI.arm .note.gnu.build-id
05 .tdata
06 .eh_frame_hdr
07
readelf -l after rewriting:
Elf file type is EXEC (Executable file)
Entry point 0x202a0
There are 8 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x000964 0x10020964 0x10020964 0x00230 0x00230 R 0x4
LOAD 0x010000 0x00020000 0x00020000 0x20000 0x20000 R E 0x10000
LOAD 0x000000 0x10020000 0x10020000 0x00c1c 0x00c1c R 0x10000
LOAD 0x000c20 0x10030c20 0x10030c20 0x00b18 0x010b4 RW 0x10000
NOTE 0x000134 0x10020134 0x10020134 0x0003c 0x0003c R 0x4
TLS 0x000c20 0x10030c20 0x10030c20 0x00478 0x00478 R 0x8
GNU_EH_FRAME 0x000b94 0x10020b94 0x10020b94 0x00014 0x00014 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10
Section to Segment mapping:
Segment Sections...
00
01 .fini .comment .ARM.attributes .debug_aranges .debug_info
.debug_abbrev
02
03 .bss
04
05
06
07
What might be the reason behind this?

What might be the reason behind this?
The most likely reason is that whatever tool you used overwrote more than just some instructions from .text.
In particular, it appears to have overwritten your section table. You can compare the before/after output from readelf -WS to confirm this, or even readelf -W --all to see what else might have been overwritten.

Related

Where does the text segment actually start? [duplicate]

There is a remote 64-bit *nix server that can compile a user-provided code (which should be written in Rust, but I don't think it matters since it uses LLVM). I don't know which compiler/linker flags it uses, but the compiled ELF executable looks weird - it has 4 LOAD segments:
$ readelf -e executable
...
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
...
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000004138 0x0000000000004138 R 0x1000
LOAD 0x0000000000005000 0x0000000000005000 0x0000000000005000
0x00000000000305e9 0x00000000000305e9 R E 0x1000
LOAD 0x0000000000036000 0x0000000000036000 0x0000000000036000
0x000000000000d808 0x000000000000d808 R 0x1000
LOAD 0x0000000000043da0 0x0000000000044da0 0x0000000000044da0
0x0000000000002290 0x00000000000024a0 RW 0x1000
...
On my own system all executables that I was looking at only have 2 LOAD segments:
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
...
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000003000c0 0x00000000003000c0 R E 0x200000
LOAD 0x00000000003002b0 0x00000000005002b0 0x00000000005002b0
0x00000000000776c8 0x000000000009b200 RW 0x200000
...
What are the circumstances (compiler/linker versions, flags etc) under which a compiler might build an ELF with 4 LOAD segments?
What is the point of having 4 LOAD segments? I imagine that having a segment with read but not execute permission might help against certain exploits, but why have two such segments?
A typical BFD-ld or Gold linked Linux executable has 2 loadable segments, with the ELF header merged with .text and .rodata into the first RE segment, and .data, .bss and other writable sections merged into the second RW segment.
Here is the typical section to segment mapping:
$ echo "int foo; int main() { return 0;}" | clang -xc - -o a.out-gold -fuse-ld=gold
$ readelf -Wl a.out-gold
Elf file type is EXEC (Executable file)
Entry point 0x400420
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R 0x8
INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0006b0 0x0006b0 R E 0x1000
LOAD 0x000e18 0x0000000000401e18 0x0000000000401e18 0x0001f8 0x000200 RW 0x1000
DYNAMIC 0x000e28 0x0000000000401e28 0x0000000000401e28 0x0001b0 0x0001b0 RW 0x8
NOTE 0x000254 0x0000000000400254 0x0000000000400254 0x000020 0x000020 R 0x4
GNU_EH_FRAME 0x00067c 0x000000000040067c 0x000000000040067c 0x000034 0x000034 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x000e18 0x0000000000401e18 0x0000000000401e18 0x0001e8 0x0001e8 RW 0x8
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .dynsym .dynstr .gnu.hash .hash .gnu.version .gnu.version_r .rela.dyn .init .text .fini .rodata .eh_frame .eh_frame_hdr
03 .fini_array .init_array .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag
06 .eh_frame_hdr
07
08 .fini_array .init_array .dynamic .got .got.plt
This optimizes the number of mmaps that the kernel must perform to load such executable, but at a security cost: the data in .rodata shouldn't be executable, but is (because it's merged with .text, which must be executable). This may significantly increase the attack surface for someone trying to hijack a process.
Newer Linux systems, in particular using LLD to link binaries, prioritize security over speed, and put ELF header and .rodata into the first R-only segment, resulting in 3 load segments and improved security. Here is a typical mapping:
$ echo "int foo; int main() { return 0;}" | clang -xc - -o a.out-lld -fuse-ld=lld
$ readelf -Wl a.out-lld
Elf file type is EXEC (Executable file)
Entry point 0x201000
There are 10 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000200040 0x0000000000200040 0x000230 0x000230 R 0x8
INTERP 0x000270 0x0000000000200270 0x0000000000200270 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000200000 0x0000000000200000 0x000558 0x000558 R 0x1000
LOAD 0x001000 0x0000000000201000 0x0000000000201000 0x000185 0x000185 R E 0x1000
LOAD 0x002000 0x0000000000202000 0x0000000000202000 0x001170 0x002005 RW 0x1000
DYNAMIC 0x003010 0x0000000000203010 0x0000000000203010 0x000150 0x000150 RW 0x8
GNU_RELRO 0x003000 0x0000000000203000 0x0000000000203000 0x000170 0x001000 R 0x1
GNU_EH_FRAME 0x000440 0x0000000000200440 0x0000000000200440 0x000034 0x000034 R 0x1
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0
NOTE 0x00028c 0x000000000020028c 0x000000000020028c 0x000020 0x000020 R 0x4
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .rodata .dynsym .gnu.version .gnu.version_r .gnu.hash .hash .dynstr .rela.dyn .eh_frame_hdr .eh_frame
03 .text .init .fini
04 .data .tm_clone_table .fini_array .init_array .dynamic .got .bss
05 .dynamic
06 .fini_array .init_array .dynamic .got
07 .eh_frame_hdr
08
09 .note.ABI-tag
Not to be left behind, the newer BFD-ld (my version is 2.31.1) also makes ELF header and .rodata read-only, but fails to merge two R-only segments into one, resulting in 4 loadable segments:
$ echo "int foo; int main() { return 0;}" | clang -xc - -o a.out-bfd -fuse-ld=bfd
$ readelf -Wl a.out-bfd
Elf file type is EXEC (Executable file)
Entry point 0x401020
There are 11 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x000268 0x000268 R 0x8
INTERP 0x0002a8 0x00000000004002a8 0x00000000004002a8 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0003f8 0x0003f8 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x00018d 0x00018d R E 0x1000
LOAD 0x002000 0x0000000000402000 0x0000000000402000 0x000110 0x000110 R 0x1000
LOAD 0x002e40 0x0000000000403e40 0x0000000000403e40 0x0001e8 0x0001f0 RW 0x1000
DYNAMIC 0x002e50 0x0000000000403e50 0x0000000000403e50 0x0001a0 0x0001a0 RW 0x8
NOTE 0x0002c4 0x00000000004002c4 0x00000000004002c4 0x000020 0x000020 R 0x4
GNU_EH_FRAME 0x002004 0x0000000000402004 0x0000000000402004 0x000034 0x000034 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x002e40 0x0000000000403e40 0x0000000000403e40 0x0001c0 0x0001c0 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn
03 .init .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .dynamic .got .got.plt .data .bss
06 .dynamic
07 .note.ABI-tag
08 .eh_frame_hdr
09
10 .init_array .fini_array .dynamic .got
Finally, some of these choices are affected by the --(no)rosegment (or -Wl,z,noseparate-code for BFD ld) linker option.

How to map the section to the segment from an ELF output file?

Well I have written a bootloader in assembly and trying to load a C kernel from it.
This is the bootloader:
bits 16
xor ax,ax
jmp 0x0000:boot
extern kernel_main
global boot
boot:
mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory
mov dl, 0x80 ; sector read from fixed/usb disk ;0 for floppy; 0x80 for hd
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, 0x8000 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt
mov ax, 0x2401
int 0x15 ; enable A20 bit
mov ax, 0x3
int 0x10 ; set vga text mode 3
cli
lgdt [gdt_pointer] ; load the gdt table
mov eax, cr0
or eax,0x1 ; set the protected mode bit on special CPU reg cr0
mov cr0, eax
jmp CODE_SEG:boot2 ; long jump to the code segment
gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_pointer:
dw gdt_end - gdt_start
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
bits 32
boot2:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; mov esi,hello
; mov ebx,0xb8000
;.loop:
; lodsb
; or al,al
; jz haltz
; or eax,0x0100
; mov word [ebx], ax
; add ebx,2
; jmp .loop
;haltz:
;hello: db "Hello world!",0
mov esp,kernel_stack_top
jmp kernel_main
cli
hlt
times 510 -($-$$) db 0
dw 0xaa55
section .bss
align 4
kernel_stack_bottom: equ $
resb 16384 ; 16 KB
kernel_stack_top:
and this is the C kernel:
__asm__("cli\n");
void kernel_main(void){
const char string[] = "012345678901234567890123456789012345678901234567890123456789012";
volatile unsigned char* vid_mem = (unsigned char*) 0xb8000;
int j=0;
while(string[j]!='\0'){
*vid_mem++ = (unsigned char) string[j++];
*vid_mem++ = 0x09;
}
for(;;);
}
Now I am compiling both the source separately into an ELF output file.
And linking them through a linker script and output a raw binary file and load it with qemu.
Linker script:
ENTRY(boot)
OUTPUT_FORMAT("binary")
SECTIONS{
. = 0x7c00;
.boot1 : {
*(.boot)
}
.kernel : AT(0x7e00){
*(.text)
*(.rodata)
*(.data)
_bss_start = .;
*(.bss)
*(COMMON)
_bss_end = .;
*(.comment)
*(.symtab)
*(.shstrtab)
*(.strtab)
}
/DISCARD/ : {
*(.eh_frame)
}
}
with a build script:
nasm -f elf32 boot.asm -o boot.o
/home/rakesh/Desktop/cross-compiler/i686-elf-4.9.1-Linux-x86_64/bin/i686-elf-gcc -m32 kernel.c -o kernel.o -e kernel_main -Ttext 0x0 -nostdlib -ffreestanding -std=gnu99 -mno-red-zone -fno-exceptions -nostdlib -Wall -Wextra
/home/rakesh/Desktop/cross-compiler/i686-elf-4.9.1-Linux-x86_64/bin/i686-elf-ld boot.o kernel.o -o kernel.bin -T linker3.ld
qemu-system-x86_64 kernel.bin
But I am running into a little problem.
notice that string in the C kernel
const char string[] = "012345678901234567890123456789012345678901234567890123456789012";
when its size is equal to or less than 64 bytes (along with the null termination). then the program works correctly.
however when the string size increases from 64 bytes then the program seems to not work
I was trying to debug it myself and observed that when the string size is less than or equal to 64 bytes then the output ELF file, the kernel.o have following contents :
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x1
Start of program headers: 52 (bytes into file)
Start of section headers: 4412 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 7
Section header string table index: 4
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 001000 0000bd 00 AX 0 0 1
[ 2] .eh_frame PROGBITS 000000c0 0010c0 000034 00 A 0 0 4
[ 3] .comment PROGBITS 00000000 0010f4 000011 01 MS 0 0 1
[ 4] .shstrtab STRTAB 00000000 001105 000034 00 0 0 1
[ 5] .symtab SYMTAB 00000000 001254 0000a0 10 6 6 4
[ 6] .strtab STRTAB 00000000 0012f4 00002e 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x00000000 0x00000000 0x000f4 0x000f4 R E 0x1000
Section to Segment mapping:
Segment Sections...
00 .text .eh_frame
There is no dynamic section in this file.
There are no relocations in this file.
The decoding of unwind sections for machine type Intel 80386 is not currently supported.
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 000000c0 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 FILE LOCAL DEFAULT ABS kernel.c
5: 00000000 0 FILE LOCAL DEFAULT ABS
6: 00000001 188 FUNC GLOBAL DEFAULT 1 kernel_main
7: 000010f4 0 NOTYPE GLOBAL DEFAULT 2 __bss_start
8: 000010f4 0 NOTYPE GLOBAL DEFAULT 2 _edata
9: 000010f4 0 NOTYPE GLOBAL DEFAULT 2 _end
No version information found in this file.
However when the size of the string is more than 64 bytes the contents are like this:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x1
Start of program headers: 52 (bytes into file)
Start of section headers: 4432 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 8
Section header string table index: 5
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 001000 000083 00 AX 0 0 1
[ 2] .rodata PROGBITS 00000084 001084 000041 00 A 0 0 4
[ 3] .eh_frame PROGBITS 000000c8 0010c8 000038 00 A 0 0 4
[ 4] .comment PROGBITS 00000000 001100 000011 01 MS 0 0 1
[ 5] .shstrtab STRTAB 00000000 001111 00003c 00 0 0 1
[ 6] .symtab SYMTAB 00000000 001290 0000b0 10 7 7 4
[ 7] .strtab STRTAB 00000000 001340 00002e 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x00000000 0x00000000 0x00100 0x00100 R E 0x1000
Section to Segment mapping:
Segment Sections...
00 .text .rodata .eh_frame
There is no dynamic section in this file.
There are no relocations in this file.
The decoding of unwind sections for machine type Intel 80386 is not currently supported.
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000084 0 SECTION LOCAL DEFAULT 2
3: 000000c8 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 FILE LOCAL DEFAULT ABS kernel.c
6: 00000000 0 FILE LOCAL DEFAULT ABS
7: 00000001 130 FUNC GLOBAL DEFAULT 1 kernel_main
8: 00001100 0 NOTYPE GLOBAL DEFAULT 3 __bss_start
9: 00001100 0 NOTYPE GLOBAL DEFAULT 3 _edata
10: 00001100 0 NOTYPE GLOBAL DEFAULT 3 _end
No version information found in this file.
I noticed that the string is now in the .rodata section with a size of 41 hex or 65 bytes, which has to be mapped to a segment, possibly the 0th segment which is NULL.
And that the program is unable to find the .rodata.
I am unable to make it work. I understand the ELF structure but I don't know how to work with them.
Two serious issues cause most of the problems are:
You load the second sector of the disk to 0x0000:0x8000 when all of the code expect the kernel to be loaded after the bootloader at 0x0000:0x7e00
You compile your kernel.c straight to an executable name kernel.o. You should compile it to a proper object file so it can go through the expected linking phase when you run ld.
To fix the problem with the kernel being loaded into memory at the wrong memory location, change:
mov bx, 0x8000 ; load into es:bx segment :offset of buffer
to:
mov bx, 0x7e00 ; load into es:bx segment :offset of buffer
To fix the issue of compiling kernel.cto an executable ELF file named kernel.o remove the -e kernel_main -Ttext 0x0 and replace it with -c. -c option forces GCC to produce an object file that can be properly linked with LD. Change:
/home/rakesh/Desktop/cross-compiler/i686-elf-4.9.1-Linux-x86_64/bin/i686-elf-gcc -m32 kernel.c -o kernel.o -e kernel_main -Ttext 0x0 -nostdlib -ffreestanding -std=gnu99 -mno-red-zone -fno-exceptions -nostdlib -Wall -Wextra
to:
/home/rakesh/Desktop/cross-compiler/i686-elf-4.9.1-Linux-x86_64/bin/i686-elf-gcc -m32 -c kernel.c -o kernel.o -nostdlib -ffreestanding -std=gnu99 -mno-red-zone -fno-exceptions -Wall -Wextra
Reason for Failure with Longer Strings
The reason the string with less than 64 bytes worked is because the compiler generated code in a position independent way by initializing the array on the stack with immediate values. When the size reached 64 bytes the compiler placed the string into the .rodata section and then initialized the array on the stack by copying it from the .rodata. This made your code position dependent. Your code was loaded at the wrong offsets and had incorrect origin points yielding code referencing incorrect addresses, so it failed.
Other Observations
You should initialize your BSS (.bss) section to 0 before calling kernel_main. This can be done in assembly by iterating through all the bytes from offset _bss_start to offset _bss_end.
The .comment section will be emitted into your binary file wasting bytes as a result. You should put it in the /DISCARD/ section.
You should place the BSS section in your linker script after all the others so it doesn't take up space in kernel.bin
In boot.asm you should set SS:SP (stack pointer) near the beginning before reading disk sectors. It should be set to a place that won't interfere with your code. This is especially important when reading data into memory from disk since you don't know where the BIOS placed the current stack. You don't want to read on top of the current stack area. Setting it just below the bootloader at 0x0000:0x7c00 should work.
Before calling into C code you should clear the direction flag to ensure string instructions use forward movement. You can do this by using the CLD instruction.
In boot.asmyou can make your code more generic by using the boot drive number passed by the BIOS in the DL register rather than hard coding it to the value 0x80 (0x80 being the first hard drive)
You might consider turning on optimization with -O3, or using optimization level -Os to optimize for code size.
Your linker script doesn't quite work the way you expect although it produces the correct results. You never declared .boot section in your NASM file so nothing actually gets placed in the .boot1 output section in the linker script. It works because it gets included in the .text section in the .kernel output section.
It is preferable to remove the padding and boot signature from the assembly file and move it to the linker script
Instead of having your linker script output a binary file directly, it is more useful to output to the default ELF executable format. You can then use OBJCOPY to convert the ELF file to a binary file. This allows you to build with debug information which will appear as part of the ELF executable. The ELF executable can be used to symbolically debug your binary kernel in QEMU.
Rather than use LD directly for linking, use GCC. This has the advantage that the libgcc library can be added without specifying the full path to the library. libgcc is a set of routines that may be needed for C code generation with GCC
Revised source code, linker script and build commands with the observations above taken into account:
boot.asm:
bits 16
section .boot
extern kernel_main
extern _bss_start
extern _bss_len
global boot
jmp 0x0000:boot
boot:
; Place realmode stack pointer below bootloader where it doesn't
; get in our way
xor ax, ax
mov ss, ax
mov sp, 0x7c00
mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory
; Remove this, DL is already set by BIOS to current boot drive number
; mov dl, 0x80 ; sector read from fixed/usb disk ;0 for floppy; 0x80 for hd
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, 0x7e00 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt
mov ax, 0x2401
int 0x15 ; enable A20 bit
mov ax, 0x3
int 0x10 ; set vga text mode 3
cli
lgdt [gdt_pointer] ; load the gdt table
mov eax, cr0
or eax,0x1 ; set the protected mode bit on special CPU reg cr0
mov cr0, eax
jmp CODE_SEG:boot2 ; long jump to the code segment
gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_pointer:
dw gdt_end - gdt_start
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
bits 32
boot2:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Zero out the BSS area
cld
mov edi, _bss_start
mov ecx, _bss_len
xor eax, eax
rep stosb
mov esp,kernel_stack_top
call kernel_main
cli
hlt
section .bss
align 4
kernel_stack_bottom: equ $
resb 16384 ; 16 KB
kernel_stack_top:
kernel.c:
void kernel_main(void){
const char string[] = "01234567890123456789012345678901234567890123456789012345678901234";
volatile unsigned char* vid_mem = (unsigned char*) 0xb8000;
int j=0;
while(string[j]!='\0'){
*vid_mem++ = (unsigned char) string[j++];
*vid_mem++ = 0x09;
}
for(;;);
}
linker3.ld:
ENTRY(boot)
SECTIONS{
. = 0x7c00;
.boot1 : {
*(.boot);
}
.sig : AT(0x7dfe){
SHORT(0xaa55);
}
. = 0x7e00;
.kernel : AT(0x7e00){
*(.text);
*(.rodata*);
*(.data);
_bss_start = .;
*(.bss);
*(COMMON);
_bss_end = .;
_bss_len = _bss_end - _bss_start;
}
/DISCARD/ : {
*(.eh_frame);
*(.comment);
}
}
Commands to build this bootloader and kernel:
nasm -g -F dwarf -f elf32 boot.asm -o boot.o
i686-elf-gcc -g -O3 -m32 kernel.c -c -o kernel.o -ffreestanding -std=gnu99 \
-mno-red-zone -fno-exceptions -Wall -Wextra
i686-elf-gcc -nostdlib -Wl,--build-id=none -T linker3.ld boot.o kernel.o \
-lgcc -o kernel.elf
objcopy -O binary kernel.elf kernel.bin
To symbolically debug the 32-bit kernel with QEMU you can launch QEMU this way:
qemu-system-i386 -fda kernel.bin -S -s &
gdb kernel.elf \
-ex 'target remote localhost:1234' \
-ex 'break *kernel_main' \
-ex 'layout src' \
-ex 'continue'
This will start up your kernel.bin file in QEMU and then remotely connect the GDB debugger. The layout should show the source code and break on kernel_main.

What does loadable mean in microcontrollers in the sense of linikers

I'm trying to get familiar with the linking and startup procedures in ARM Cortex-M4 microcontrollers. Looking through the linker scripts almost all the sections are marked as loadable.
At first I thought that meant it would be copied from flash to RAM, but then I learned that doing that is handled in a different way. So what does it mean for a section in flash to be loadable? Isn't it already loaded and run from the location in flash? Also, I'm referring to a section section containing instructions.
Does loadable in this context mean loading by the debugger into the device?
a fully functional cortex-m program
flash.s
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.align
.thumb_func
.globl dummy
dummy:
bx lr
so.c
void dummy ( unsigned int );
int notmain ( void )
{
unsigned int ra;
for(ra=0;ra<10;ra++) dummy(ra);
return(0);
}
flash.ld
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
build
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -c so.c -o so.o
arm-none-eabi-ld -o so.elf -T flash.ld flash.o so.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary
(can use cortex-m4 either works)
so.list
00000000 <_start>:
0: 20001000 andcs r1, r0, r0
4: 00000011 andeq r0, r0, r1, lsl r0
8: 00000017 andeq r0, r0, r7, lsl r0
c: 00000017 andeq r0, r0, r7, lsl r0
00000010 <reset>:
10: f000 f804 bl 1c <notmain>
14: e7ff b.n 16 <hang>
00000016 <hang>:
16: e7fe b.n 16 <hang>
00000018 <dummy>:
18: 4770 bx lr
1a: 46c0 nop ; (mov r8, r8)
0000001c <notmain>:
1c: b510 push {r4, lr}
1e: 2400 movs r4, #0
20: 0020 movs r0, r4
22: 3401 adds r4, #1
24: f7ff fff8 bl 18 <dummy>
28: 2c0a cmp r4, #10
2a: d1f9 bne.n 20 <notmain+0x4>
2c: 2000 movs r0, #0
2e: bc10 pop {r4}
30: bc02 pop {r1}
32: 4708 bx r1
being a less complicated linker script and program the elf has less stuff
part of readelf
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 010000 000034 00 AX 0 0 4
[ 2] .ARM.attributes ARM_ATTRIBUTES 00000000 010034 00002d 00 0 0 1
[ 3] .comment PROGBITS 00000000 010061 000011 01 MS 0 0 1
[ 4] .symtab SYMTAB 00000000 010074 0000f0 10 5 12 4
[ 5] .strtab STRTAB 00000000 010164 00003d 00 0 0 1
[ 6] .shstrtab STRTAB 00000000 0101a1 00003a 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x00000000 0x00000000 0x00034 0x00034 R E 0x10000
hexdump -C so.bin
00000000 00 10 00 20 11 00 00 00 17 00 00 00 17 00 00 00 |... ............|
00000010 00 f0 04 f8 ff e7 fe e7 70 47 c0 46 10 b5 00 24 |........pG.F...$|
00000020 20 00 01 34 ff f7 f8 ff 0a 2c f9 d1 00 20 10 bc | ..4.....,... ..|
00000030 02 bc 08 47 |...G|
00000034
a "binary" comes in many flavors, it is an unfortunately poorly named term as it is so confusing. Everything you see in the disassembly above is required for the program to run, that is the real binary part of this, it has to be loaded wherever you need it loaded to run. if on an operating system then the operating system reads the elf file extracts the loadable sections with their addresses/offsets and loads them into memory before launching at the entry point. Take advantage of tools already having the elf file format and we can re-use some of that for microcontrollers, we cant/dont normally use the entry point as that makes no sense, we have to make the vector/entry point match what the hardware needs, in this case a vector table.
The hexdump coming from the objcopy also shows the parts we have to have visible to the processor for the program to run, or loaded in address/memory space (flash is in memory or address space in this case).
But the "binary" file, the elf also contains debug symbols in case you want to pull up a debugger, add some more options on the toolchain command line and you get even more information about where these items are in the source code file so you could in some cases see the high level langauge when single stepping through code. Those are not loadable sections, they are descriptive of the program or just there to help out, they are not machine code nor data that the processor needs to execute the program so they do not need to be loaded into the memory space.
yet another "binary" file format
arm-none-eabi-objcopy so.elf -O ihex so.hex
cat so.hex
:100000000010002011000000170000001700000081
:1000100000F004F8FFE7FEE77047C04610B5002483
:1000200020000134FFF7F8FF0A2CF9D1002010BCA2
:0400300002BC0847BF
:00000001FF
it has a little extra information but almost all of it is the part we have to load into the address space for the program to run
another binary file format
S00A0000736F2E7372656338
S1130000001000201100000017000000170000007D
S113001000F004F8FFE7FEE77047C04610B500247F
S113002020000134FFF7F8FF0A2CF9D1002010BC9E
S107003002BC0847BB
S9030000FC
also most of it is program.
elf is just another file format (fairly popular with gnu tools, but still just another file format), it contains the machine code and data required plus a bunch of other stuff, the machine code and data is what we have to load into ram if this is an operating system, or what we ideally load into flash for a microcontroller, but not all microcontrollers are equal some are ram only based and the program is downloaded via usb during enumeration (into ram). and other solutions, or if debugging you could probably have items loaded into ram depending on the mcu and tools, although that is not how the thing boots so that wouldnt really be a good binary.
if you feel the need to zero .bss and to have any .data then you need additional information, the offset and size of .bss and the offset and contents of .data, the bootstrap then zeros and copies those items, and you need that information in the non-volatile flash/rom, it is just more data that is required of the machine code and data needed to run the program. If you are letting others write the code for you then there are possibly tailored linker scripts and bootstrap code that allows you to just have .data items and push a build button on a gui and it all magically is in place when your entry point (main() by convention and or standard) starts execution or the code that represents your high level code at the C entry point.

Gameboy emulation - Clarification need on CD instruction

I'm currently in the process of writing a Gameboy emulator, and I've noticed something that seems strange to me.
My emulator is hitting a jump instruction 0xCD, for example CD B6 FF, but my understanding was that a jump should only be jumping to an address within cartridge ROM (0x7FFF maximum), because I'm assuming the CPU can only execute instructions from ROM, not RAM. The ROM in question is Dr. Mario, which I'd expect to only be carrying out valid operations. 0xFFB6 is in high RAM, which seems odd to me.
Am I correct in my thinking? If I am, presumably that means my program counter is somehow ending up at the wrong address and that the CB is actually part of another instruction's data, and not an instruction itself?
I'd be grateful for some clarification, thanks.
For reference, I've been using Gameboy Opcodes and CPU docs to implement the instructions. I know they contain a few errors, and I think I've accounted for them (for example, 0xE2 being listed as a two-byte instruction, when it's only one)
Just checked Dr. Mario 1.1, it copies the VBlank int routine at hFFB6 at startup, then when VBlank happens, the routine at 0:01A6 is called, which calls the OAM DMA transfer routine.
During OAM DMA transfer, the CPU can only access HRAM, so writing a short routine in HRAM that will wait for the transfer to be completed is required. The OAM DMA transfer takes 160 µs, so you usually make a loop that will wait this amount of time after specifying the OAM transfer source.
This is the part of the initialization routine run at startup that copies the DMA transfer routine to HRAM:
...
ROM0:027E 0E B6 ld c,B6 ;destination hFFB6
ROM0:0280 06 0A ld b,0A ;length 0xA
ROM0:0282 21 86 23 ld hl,2386 ;source 0:2386
ROM0:0285 2A ldi a,(hl) ;copy OAM DMA transfer routine from source
ROM0:0286 E2 ld (ff00+c),a ;paste to destination
ROM0:0287 0C inc c ;destination++
ROM0:0288 05 dec b ;length--
ROM0:0289 20 FA jr nz,0285 ;loop until DMA transfer routine is copied
...
When VBlank happens, it jumps to the routine at 0:01A6:
ROM0:0040 C3 A6 01 jp 01A6
Which contains a call to our OAM DMA transfer routine, waiting for DMA to be completed:
ROM0:01A6 F5 push af
ROM0:01A7 C5 push bc
ROM0:01A8 D5 push de
ROM0:01A9 E5 push hl
ROM0:01AA F0 B1 ld a,(ff00+B1)
ROM0:01AC A7 and a
ROM0:01AD 28 0B jr z,01BA
ROM0:01AF FA F1 C4 ld a,(C4F1)
ROM0:01B2 A7 and a
ROM0:01B3 28 05 jr z,01BA
ROM0:01B5 F0 EF ld a,(ff00+EF)
ROM0:01B7 A7 and a
ROM0:01B8 20 09 jr nz,01C3
ROM0:01BA F0 E1 ld a,(ff00+E1)
ROM0:01BC FE 03 cp a,03
ROM0:01BE 28 03 jr z,01C3
ROM0:01C0 CD B6 FF call FFB6 ;OAM DMA transfer routine is in HRAM
...
OAM DMA transfer routine:
HRAM:FFB6 3E C0 ld a,C0
HRAM:FFB8 E0 46 ld (ff00+46),a ;source is wC000
HRAM:FFBA 3E 28 ld a,28 ;loop start
HRAM:FFBC 3D dec a
HRAM:FFBD 20 FD jr nz,FFBC ;wait for the OAM DMA to be completed
HRAM:FFBF C9 ret ;ret to 0:01C3
Here is my analysis:
Looking for CD B6 FF in the raw ROM I can only find it in one place of the memory which is 0x01C0 (448 in decimal).
So I decided to disassemble the ROM, to see if it is a valid instruction.
I used gb-disasm to disassemble the ROM. Here are the values from 0x150 (ROM start) to address 0x201.
[0x00000100] 0x00 NOP
[0x00000101] 0xC3 0x50 0x01 JP $0150
[0x00000150] 0xC3 0xE8 0x01 JP $01E8
[0x00000153] 0x01 0x0E 0xD0 LD BC,$D00E
[0x00000156] 0x0A LD A,[BC]
[0x00000157] 0xA7 AND A
[0x00000158] 0x20 0x0D JR NZ,$0D ; 0x167
[0x0000015A] 0xF0 0xCF LDH A,[$CF] ; HIMEM
[0x0000015C] 0xFE 0xFE CP $FE
[0x0000015E] 0x20 0x04 JR NZ,$04 ; 0x164
[0x00000160] 0x3E 0x01 LD A,$01
[0x00000162] 0x18 0x01 JR $01 ; 0x165
[0x00000164] 0xAF XOR A
[0x00000165] 0x02 LD [BC],A
[0x00000166] 0xC9 RET
[0x00000167] 0xFA 0x46 0xD0 LD A,[$D046]
[0x0000016A] 0xE0 0x01 LDH [$01],A ; SB
[0x0000016C] 0x18 0xF6 JR $F6 ; 0x164
[0x000001E8] 0xAF XOR A
[0x000001E9] 0x21 0xFF 0xDF LD HL,$DFFF
[0x000001EC] 0x0E 0x10 LD C,$10
[0x000001EE] 0x06 0x00 LD B,$00
[0x000001F0] 0x32 LD [HLD],A
[0x000001F1] 0x05 DEC B
[0x000001F2] 0x20 0xFC JR NZ,$FC ; 0x1F0
[0x000001F4] 0x0D DEC C
[0x000001F5] 0x20 0xF9 JR NZ,$F9 ; 0x1F0
[0x000001F7] 0x3E 0x0D LD A,$0D
[0x000001F9] 0xF3 DI
[0x000001FA] 0xE0 0x0F LDH [$0F],A ; IF
[0x000001FC] 0xE0 0xFF LDH [$FF],A ; IE
[0x000001FE] 0xAF XOR A
[0x000001FF] 0xE0 0x42 LDH [$42],A ; SCY
[0x00000201] 0xE0 0x43 LDH [$43],A ; SCX
The way we have to disassemble a ROM is by following the flow of instructions. For example, we know that the main program starts at position 0x150. So we should start disassembling there. Then we follow instruction by instruction until we hit any JUMP instruction (JP, JR, CALL, RET, etc). From that moment on the flow of the program is forked in two and we should follow both paths to disassemble.
The think to understand here is that if I show you a random memory position in a ROM, you cannot tell me if it is data or instructions. The only way to find out is by following the program flow. We need to define blocks of code that start in a jump destination and end in another jump instruction.
gb-disasm skips any memory position that is not inside a code block. 0x16C marks the end of a block.
[0x0000016C] 0x18 0xF6 JR $F6 ; 0x164
The next block starts on 0x1E8. We know that because it is the destination address of a jump located on 0x150.
[0x00000150] 0xC3 0xE8 0x01 JP $01E8
Memory block from 0x16E until 0x1E8 is not consider a code block. That's why you don't see the memory position 0x01C0 listed as an instruction.
So there you are, it is very likely that you are interpreting the instructions in a wrong way. If you want to be 100% sure, you can disassemble the whole room and check if any instruction points to 0x16E-0x1E8 and reads it as raw data, such as a tile or something.
Please leave a comment if you agree with the analysis.

When is an ELF .text segment not an ELF .text segment?

I'm having trouble finding appropriate documentation for the problem I'm having generating consistent HMACs in the kernel and user space. According to Robert Love in Linux Kernel Development, the Memory Descriptors mm->start_code and mm->end_code are supposed to contain the .text segment. Finding the .text segment in a static executable is well defined in the ELF documentation and is easy to get at. So, given the following two code snippets, one would expect to get a matching HMAC:
Kernel:
__mm = get_task_mm(__task);
__retcode = ntru_crypto_hmac_init(__crypto_context);
if(__retcode != NTRU_CRYPTO_HMAC_OK)
return 1;
__retcode = ntru_crypto_hmac_update(__crypto_context, (const uint8_t*)__mm->start_code,
__mm->end_code - __mm->start_code);
if(__retcode != NTRU_CRYPTO_HMAC_OK)
return 1;
__retcode = ntru_crypto_hmac_final(__crypto_context, __hmac);
if(__retcode != NTRU_CRYPTO_HMAC_OK)
return 1;
return 0;
Userland:
for (j = 0; j < file_hdr32.e_shnum; j++)
{
if (!strcmp(".text", strIndex + section_hdr32[j]->sh_name))
{
retcode = ntru_crypto_hmac_init(__crypto_context());
if(retcode != NTRU_CRYPTO_HMAC_OK)
{
syslog(LOG_ERR, "ntru_crypto_hmac_init error: retcode = %d, TID(0x%lx)",
retcode,pthread_self());
return 0;
}
retcode = ntru_crypto_hmac_update(__crypto_context(),
filebuf + section_hdr32[j]->sh_offset, section_hdr32[j]->sh_size);
if(retcode != NTRU_CRYPTO_HMAC_OK)
{
syslog(LOG_ERR, "Internal crypto error (%d)", retcode);
return 0;
}
retcode = ntru_crypto_hmac_final(__crypto_context(), _hmac);
if(retcode != NTRU_CRYPTO_HMAC_OK)
{
syslog(LOG_ERR, "Failed to finalize HMAC, TID(0x%lx)", pthread_self());
return 0;
}
return 1;
}
}
In both cases the .text segment is exactly where it's documented to be but they never match. I've generated userland HMACs for all 17,000 executable files on the system so even if the code segment in the kernel memory descriptor were pointing to a dependency, rather than the primary executable, I still should get a match. But no dice. There's something fundamentally different between the two .text segments and I was wondering if anyone out there knew what it was so I can save some time--any clues?
There's something fundamentally different between the two ".text" segments
Your problem is that you are ignoring the difference between segments and sections.
The ELF format is an executable and linking format. Segments are used for the former, sections for the latter (and linking here means static linking, i.e. build-time). Once the binary is linked, sections can be completely discarded from it, and only segments are needed at runtime. Segments are mmaped, not sections.
Now let's look at the difference between the two.
readelf -l /bin/date
Elf file type is EXEC (Executable file)
Entry point 0x402000
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d5ac 0x000000000000d5ac R E 200000
LOAD 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x0000000000000440 0x0000000000000610 RW 200000
DYNAMIC 0x000000000000de38 0x000000000060de38 0x000000000060de38
0x00000000000001a0 0x00000000000001a0 RW 8
NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x000000000000c700 0x000000000040c700 0x000000000040c700
0x00000000000002a4 0x00000000000002a4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
GNU_RELRO 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x00000000000001f0 0x00000000000001f0 R 1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .ctors .dtors .jcr .dynamic .got
Above you can see that multiple sections (.interp, .note.ABI-tag, ... .text, ...) all got mapped into a single PT_LOAD segment. All these sections have the same protections, and all are "covered" by a single [mm->start_core, mm->end_code) region.
Compare this to the .text section:
readelf -WS /bin/date | grep '\.text'
[13] .text PROGBITS 0000000000401900 001900 0077f8 00 AX 0 0 16
You'll note that the section is smaller and begins at a different offset.
No wonder you get different HMAC then. Try computing HMAC in user-land over segments, and you should get a match.

Resources