Hand-decoding an ELF binary image
31 October 2018While recovering from some dentistry the other day I figured I’d have a go at better understanding the ELF binary format. What better way to do that than to compile a small program and hand-decode the resulting binary with a hex editor and whatever ELF format spec I could find.
Overview
Below, we’ll use nasm
to build a small assembly Hello World program to a
64-bit ELF object file, then link that into an ELF executable with GNU ld
.
Finally, we’ll run the resulting object file and binary image through xxd
and
hand-decode the resulting hex.
The code and instructions below work on FreeBSD 11 on x86_64 hardware. For other operating systems, hardware, and toolchains, you’re on your own! I’d imagine this should all work just fine on Linux. If I get bored one day, I may redo this for Mach-O binaries on macOS.
hello.asm
First we’ll bang up a minimal Hello World program in assembly. In the .data
section, we add a null-terminated string, hello
, and its length hbytes
. In
the program text, we set up and execute the write(stdout, hello, hbytes)
syscall, then set up and execute an exit(0)
syscall.
Note that 64-bit FreeBSD, macOS, and Linux all use the SysV AMD64 calling
convention. For calls against the kernel interface, the syscall number is
stored in rax
and up to six parameters are passed, in order, in rdi
, rsi
,
rdx
, r10
, r8
, r9
. For user calls, replace r10
with rcx
in this
list, and pass further arguments on the stack. In all cases, the return value
is passed through rax
. More details can be found in section A.2.1 of the
System V AMD64 ABI Reference.
; hello.asm
%define stdin 0
%define stdout 1
%define stderr 2
%define SYS_exit 1
%define SYS_write 4
%macro system 1
mov rax, %1
syscall
%endmacro
%macro sys.exit 0
system SYS_exit
%endmacro
%macro sys.write 0
system SYS_write
%endmacro
section .data
hello db 'Hello, World!', 0Ah
hbytes equ $-hello
section .text
global _start
_start:
mov rdi, stdout
mov rsi, hello
mov rdx, hbytes
sys.write
xor rdi,rdi
sys.exit
Compile to object code
Next, we’ll compile hello.asm
to a 64-bit ELF object file using nasm
:
% nasm -f elf64 hello.asm
This emits hello.o
, an 880-byte ELF-64 object file. Since we haven’t yet run
this through the linker, addresses of global symbols (in this case, hello
)
are not yet known and thus left with address 0x0 placeholders. We can see this
in the movabs
instruction at offset 0x15 of the .text
section below.
The relocation section (Section 6: .rela.text
) contains an entry for each
symbolic reference that needs to be filled in by the linker. In this case
there’s just a single entry for the symbol hello
(which points to our hello
world string). The relocation table entry’s r_offset
indicates the address to
replace is at an offset of 0x7 into the section of the associated symbol table
entry. Its r_info
(0x0000000200000001) encodes a relocation type in its lower
4 bytes (0x1: R_AMD64_64
) and the associated symbol table entry in its upper
4 bytes (0x2, which, if we look it up in the symbol table is the .text
section). The r_addend
field (0x0) specifies an additional adjustment to the
substituted symbol to be applied at link time; specifically, for the
R_AMD64_64
, the final address is computed as S + A, where S is the
substituted symbol value (in our case, the address of hello
) and A is the
addend (in our case, 0x0).
Without further ado, let’s dump the object file:
% xxd hello.o
With whatever ELF64 linker & loader guide we can find at hand, let’s get decoding this thing:
ELF Header
|00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000| .ELF............
|00000010: 0100 3e00 0100 0000 0000 0000 0000 0000| ..>.............
|00000020: 0000 0000 0000 0000 4000 0000 0000 0000| ........@.......
|00000030: 0000 0000 4000 0000 0000 4000 0700 0300| ....@.....@.....
e_ident[EI_MAG0..EI_MAG3] 0x7f + ELF Magic
e_ident[EI_CLASS] 0x02 64-bit
e_ident[EI_DATA] 0x01 Little-endian
e_ident[EI_VERSION] 0x01 ELF v1
e_ident[EI_OSABI] 0x00 System V
e_ident[EI_ABIVERSION] 0x00 Unused
e_ident[EI_PAD] 0x00000000000000 7 bytes unused padding
e_type 0x0001 ET_REL
e_machine 0x003e x86_64
e_version 0x00000001 Version 1
e_entry 0x0000000000000000 Entrypoint address (none)
e_phoff 0x0000000000000000 Program header table offset in image
e_shoff 0x0000000000000040 Section header table offset in image
e_flags 0x00000000 Architecture-dependent interpretation
e_ehsize 0x0040 Size of this ELF header (64B)
e_phentsize 0x0000 Size of program header table entry
e_phnum 0x0000 Number of program header table entries
e_shentsize 0x0040 Size of section header table entry (64B)
e_shnum 0x0007 Number of section header table entries
e_shstrndx 0x0003 Index of section header for .shstrtab
Section header table: Entry 0 (null)
|00000040: 0000 0000 0000 0000 0000 0000 0000 0000| ................
|00000050: 0000 0000 0000 0000 0000 0000 0000 0000| ................
|00000060: 0000 0000 0000 0000 0000 0000 0000 0000| ................
|00000070: 0000 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x00000000 Offset into .shstrtab
sh_type 0x00000000 SHT_NULL
sh_flags 0x0000000000000000 Section attributes
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000000 Offset of section in file image
sh_size 0x0000000000000000 Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000000 Alignment
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 1 (.data)
|00000080: 0100 0000 0100 0000 0300 0000 0000 0000| ................
|00000090: 0000 0000 0000 0000 0002 0000 0000 0000| ................
|000000a0: 0e00 0000 0000 0000 0000 0000 0000 0000| ................
|000000b0: 0400 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x00000001 Offset into .shstrtab
sh_type 0x00000001 SHT_PROGBITS
sh_flags 0x0000000000000003 SHF_WRITE | SHF_ALLOC
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000200 Offset of section in file image
sh_size 0x000000000000000e Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000004 Alignment
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 2 (.text)
|000000c0: 0700 0000 0100 0000 0600 0000 0000 0000| ................
|000000d0: 0000 0000 0000 0000 1002 0000 0000 0000| ................
|000000e0: 2500 0000 0000 0000 0000 0000 0000 0000| %...............
|000000f0: 1000 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x00000007 Offset into .shstrtab
sh_type 0x00000001 SHT_PROGBITS
sh_flags 0x0000000000000006 SHF_ALLOC | SHF_EXECINSTR
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000210 Offset of section in file image
sh_size 0x0000000000000025 Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000001 Alignment
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 3 (.shstrtab)
|00000100: 0d00 0000 0300 0000 0000 0000 0000 0000| ................
|00000110: 0000 0000 0000 0000 4002 0000 0000 0000| ........@.......
|00000120: 3200 0000 0000 0000 0000 0000 0000 0000| 2...............
|00000130: 0100 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x0000000d Offset into .shstrtab
sh_type 0x00000003 SHT_STRTAB
sh_flags 0x0000000000000000 Section attributes
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000240 Offset of section in file image
sh_size 0x0000000000000032 Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000001 Alignment
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 4 (.symtab)
|00000140: 1700 0000 0200 0000 0000 0000 0000 0000| ................
|00000150: 0000 0000 0000 0000 8002 0000 0000 0000| ................
|00000160: a800 0000 0000 0000 0500 0000 0600 0000| ................
|00000170: 0800 0000 0000 0000 1800 0000 0000 0000| ................
sh_name 0x00000017 Offset into .shstrtab
sh_type 0x00000002 SHT_SYMTAB
sh_flags 0x0000000000000000 Section attributes
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000280 Offset of section in file image
sh_size 0x00000000000000a8 Size in bytes of section in file image
sh_link 0x00000005 Section index of associated section
sh_info 0x00000006 Extra info about section
sh_addralign 0x0000000000000008 Alignment
sh_entsize 0x0000000000000018 Size in bytes of each entry
Section header table: Entry 5 (.strtab)
|00000180: 1f00 0000 0300 0000 0000 0000 0000 0000| ................
|00000190: 0000 0000 0000 0000 3003 0000 0000 0000| ........0.......
|000001a0: 1f00 0000 0000 0000 0000 0000 0000 0000| ................
|000001b0: 0100 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x0000001f Offset into .shstrtab
sh_type 0x00000003 SHT_STRTAB
sh_flags 0x0000000000000000 Section attributes
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000330 Offset of section in file image
sh_size 0x000000000000001f Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000001 Alignment
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 6 (.rela.text)
|000001c0: 2700 0000 0400 0000 0000 0000 0000 0000| '...............
|000001d0: 0000 0000 0000 0000 5003 0000 0000 0000| ........P.......
|000001e0: 1800 0000 0000 0000 0400 0000 0200 0000| ................
|000001f0: 0800 0000 0000 0000 1800 0000 0000 0000| ................
sh_name 0x00000027 Offset into .shstrtab
sh_type 0x00000004 SHT_RELA
sh_flags 0x0000000000000000 Section attributes
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000350 Offset of section in file image
sh_size 0x0000000000000018 Size in bytes of section in file image
sh_link 0x00000004 Section index of associated section
sh_info 0x00000002 Extra info about section
sh_addralign 0x0000000000000008 Alignment
sh_entsize 0x0000000000000018 Size in bytes of each entry
Section 1: .data (SHT_PROGBITS; SHF_WRITE | SHF_ALLOC)
|00000200: 4865 6c6c 6f2c 2057 6f72 6c64 210a 0000| Hello, World!...
0x000000 'Hello, World!\n'
Zero-padding (2 bytes starting at 0x20e)
Section 2: .text (SHT_PROGBITS; SHF_ALLOC | SHF_EXECINSTR)
|00000210: bf01 0000 0048 be00 0000 0000 0000 00ba| .....H..........
|00000220: 0e00 0000 b804 0000 000f 0548 31ff b801| ...........H1...
|00000230: 0000 000f 0500 0000 0000 0000 0000 0000| ................
0x00000010 mov edi, 0x1
0x00000015 movabs rsi, 0x000000 (placeholder for db hello)
0x0000001f mov edx, 0xe
0x00000024 mov eax, 0x4
0x00400029 syscall
0x0040002b xor rdi, rdi
0x0040002e mov eax, 0x1
0x00400033 syscall
Zero-padding (11 bytes starting at 0x235)
Section 3: .shstrtab (SHT_STRTAB;)
|00000240: 002e 6461 7461 002e 7465 7874 002e 7368| ..data..text..sh
|00000250: 7374 7274 6162 002e 7379 6d74 6162 002e| strtab..symtab..
|00000260: 7374 7274 6162 002e 7265 6c61 2e74 6578| strtab..rela.tex
|00000270: 7400 0000 0000 0000 0000 0000 0000 0000| t...............
0x00000000: ''
0x00000001: '.data'
0x00000007: '.text'
0x0000000d: '.shstrtab'
0x00000017: '.symtab'
0x0000001f: '.strtab'
0x00000027: '.rela.text'
Zero-padding (14 bytes starting at 0x272)
Section 4: .symtab’ (SHT_SYMTAB;)
Symbol table entry 0
|00000280: 0000 0000 0000 0000 0000 0000 0000 0000| ................
|00000290: 0000 0000 0000 0000 | ........
st_name 0x00000000
st_info 0x00
st_other 0x00
st_shndx 0x0000 (SHN_UNDEF)
st_value 0x0000000000000000
st_size 0x0000000000000000
Symbol table entry 1 (hello.asm)
|00000298: 0100 0000 0400 f1ff| ........
|000002a0: 0000 0000 0000 0000 0000 0000 0000 0000| ................
st_name 0x00000001
st_info 0x04 (STT_FILE)
st_other 0x00
st_shndx 0xfff1 (SHN_ABS)
st_value 0x0000000000000000
st_size 0x0000000000000000
Symbol table entry 2
|000002b0: 0000 0000 0300 0100 0000 0000 0000 0000| ................
|000002c0: 0000 0000 0000 0000 | ........
st_name 0x00000000
st_info 0x03 (STT_OBJECT | STT_FUNC)
st_other 0x00
st_shndx 0x0001 (Section 1: .data)
st_value 0x0000000000000000
st_size 0x0000000000000000
Symbol table entry 3
|000002c8: 0000 0000 0300 0200| ........
|000002d0: 0000 0000 0000 0000 0000 0000 0000 0000| ................
st_name 0x00000000
st_info 0x03 (STT_OBJECT | STT_FUNC)
st_other 0x00
st_shndx 0x0002 (Section 2: .text)
st_value 0x0000000000000000
st_size 0x0000000000000000
Symbol table entry 4 (hello)
|000002e0: 0b00 0000 0000 0100 0000 0000 0000 0000| ................
|000002f0: 0000 0000 0000 0000 | ........
st_name 0x0000000b
st_info 0x00
st_other 0x00
st_shndx 0x0001 (Section 1: .data)
st_value 0x0000000000000000
st_size 0x0000000000000000
Symbol table entry 5 (hbytes)
|000002f8: 1100 0000 0000 f1ff| ........
|00000300: 0e00 0000 0000 0000 0000 0000 0000 0000| ................
st_name 0x00000011
st_info 0x00
st_other 0x00
st_shndx 0xfff1 (SHN_ABS)
st_value 0x000000000000000e
st_size 0x0000000000000000
Symbol table entry 6 (_start)
|00000310: 1800 0000 1000 0200 0000 0000 0000 0000| ................
|00000320: 0000 0000 0000 0000 0000 0000 0000 0000| ................
st_name 0x00000018
st_info 0x01 (STT_OBJECT)
st_other 0x00
st_shndx 0x0002 (Section 2: .text)
st_value 0x0000000000000000
st_size 0x0000000000000000
Zero-padding (8 bytes starting at 0x328)
Section 5: .strtab (SHT_STRTAB;)
|00000330: 0068 656c 6c6f 2e61 736d 0068 656c 6c6f| .hello.asm.hello
|00000340: 0068 6279 7465 7300 5f73 7461 7274 0000| .hbytes._start..
0x00000000: ''
0x00000001: 'hello.asm'
0x0000000b: 'hello'
0x00000011: 'hbytes'
0x00000018: '_start'
Zero-padding (1 byte starting at 0x34f)
Section 6: .rela.text (SHT_RELA;)
|00000350: 0700 0000 0000 0000 0100 0000 0200 0000| ................
|00000360: 0000 0000 0000 0000 0000 0000 0000 0000| ................
r_offset 0x0000000000000007
r_info 0x0000000200000001 (Symbol table entry 2, type R_AMD64_64)
r_addend 0x0000000000000000
Zero-padding (8 bytes starting at 0x368)
Link to executable image
Next, let’s link hello.o
into a 64-bit ELF executable:
% ld -o hello hello.o
This emits hello
, a 951-byte ELF-64 executable image.
Since the linker has decided which segment each section maps into (if any) and
what the segment addresses are, addresses are now known for all (statically
linked) symbols, and address 0x0 placeholders have been replaced with actual
addresses. We can see this in the mov
instruction at address 0x4000b5, which
now specifies an address of 0x6000d8.
Running the linked executable image through xxd
as above and picking our
trusty linker & loader guide back up, here we go again:
ELF Header
|00000000: 7f45 4c46 0201 0109 0000 0000 0000 0000| .ELF............
|00000010: 0200 3e00 0100 0000 b000 4000 0000 0000| ..>.......@.....
|00000020: 4000 0000 0000 0000 1001 0000 0000 0000| @...............
|00000030: 0000 0000 4000 3800 0200 4000 0600 0300| ....@.8...@.....
e_ident[EI_MAG0..EI_MAG3] 0x7f + ELF Magic
e_ident[EI_CLASS] 0x02 64-bit
e_ident[EI_DATA] 0x01 Little-endian
e_ident[EI_VERSION] 0x01 ELF v1
e_ident[EI_OSABI] 0x09 FreeBSD
e_ident[EI_ABIVERSION] 0x00 Unused
e_ident[EI_PAD] 0x0000000000 7 bytes unused padding
e_type 0x0002 ET_EXEC
e_machine 0x003e x86_64
e_version 0x00000001 Version 1
e_entry 0x00000000004000b0 Entrypoint addr
e_phoff 0x0000000000000040 Program header table offset in image
e_shoff 0x0000000000000110 Section header table offset in image
e_flags 0x00000000 Architecture-dependent interpretation
e_ehsize 0x0040 Size of this ELF header
e_phentsize 0x0038 Size of program header table entry
e_phnum 0x0002 Number of program header table entries
e_shentsize 0x0040 Size of section header table entry
e_shnum 0x0006 Number of section header table entries
e_shstrndx 0x0003 Index of section header for .shstrtab
Program header table: Entry 0 (PF_X | PF_R)
|00000040: 0100 0000 0500 0000 0000 0000 0000 0000| ................
|00000050: 0000 4000 0000 0000 0000 4000 0000 0000| ..@.......@.....
|00000060: d500 0000 0000 0000 d500 0000 0000 0000| ................
|00000070: 0000 2000 0000 0000 | .. .............
p_type 0x00000001 PT_LOAD
p_flags 0x00000005 PF_X | PF_R
p_offset 0x00000000 Offset of segment in file image
p_vaddr 0x0000000000400000 Virtual address of segment in memory
p_paddr 0x0000000000400000 Physical address of segment
p_filesz 0x00000000000000d5 Size in bytes of segment in file image
p_memsz 0x00000000000000d5 Size in bytes of segment in memory
p_align 0x0000000000200000 Alignment (2MB)
Program header table: Entry 1 (PF_W | PF_R)
|00000078: 0100 0000 0600 0000| ........
|00000080: d800 0000 0000 0000 d800 6000 0000 0000| ..........`.....
|00000090: d800 6000 0000 0000 0e00 0000 0000 0000| ..`.............
|000000a0: 0e00 0000 0000 0000 0000 2000 0000 0000| .......... .....
p_type 0x00000001 PT_LOAD
p_flags 0x00000006 PF_W | PF_R
p_offset 0x00000000000000d8 Offset of segment in file image
p_vaddr 0x00000000006000d8 Virtual address of segment in memory
p_paddr 0x00000000006000d8 Physical address of segment
p_filesz 0x000000000000000e Size in bytes of segment in file image
p_memsz 0x000000000000000e Size in bytes of segment in memory
p_align 0x0000000000200000 Alignment (2MB)
Section 1: .text (SHT_PROGBITS; SHF_ALLOC | SHF_EXECINSTR)
|000000b0: bf01 0000 0048 bed8 0060 0000 0000 00ba| .....H...`......
|000000c0: 0e00 0000 b804 0000 000f 0548 31ff b801| ...........H1...
|000000d0: 0000 000f 05 | .....
0x4000b0 mov edi, 0x1
0x4000b5 movabs rsi, 0x6000d8
0x4000bf mov edx, 0xe
0x4000c4 mov eax, 0x4
0x4000c9 syscall
0x4000cb xor rdi, rdi
0x4000ce mov eax, 0x1
0x4000d3 syscall
Zero-padding (5 bytes starting at 0x000000d5)
Section 2: .data (SHT_PROGBITS; SHF_WRITE | SHF_ALLOC)
|000000d8: 4865 6c6c 6f2c 2057| Hello, W
|000000e0: 6f72 6c64 210a | orld!.
0x6000d8 'Hello, World!\n'
Section 3: .shstrtab (SHT_STRTAB;)
|000000e6: 002e 7379 6d74 6162 002e| ..symtab..
|000000f0: 7374 7274 6162 002e 7368 7374 7274 6162| strtab..shstrtab
|00000100: 002e 7465 7874 002e 6461 7461 0000 0000| ..text..data.
0x00000000: ''
0x00000001: '.symtab'
0x00000009: '.strtab'
0x00000011: '.shstrtab'
0x0000001b: '.text'
0x00000021: '.data'
Zero-padding (3 bytes starting at 0x0000010d)
Section header table: Entry 0 (null)
|00000110: 0000 0000 0000 0000 0000 0000 0000 0000| ................
|00000120: 0000 0000 0000 0000 0000 0000 0000 0000| ................
|00000130: 0000 0000 0000 0000 0000 0000 0000 0000| ................
|00000140: 0000 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x00000000 Offset into .shstrtab
sh_type 0x00000000 SHT_NULL
sh_flags 0x0000000000000000 Section attributes
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000000 Offset of section in file image
sh_size 0x0000000000000000 Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000000 Alignment
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 1 (.text)
|00000150: 1b00 0000 0100 0000 0600 0000 0000 0000| ................
|00000160: b000 4000 0000 0000 b000 0000 0000 0000| ..@.............
|00000170: 2500 0000 0000 0000 0000 0000 0000 0000| %...............
|00000180: 1000 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x0000001b Offset into .shstrtab
sh_type 0x00000001 SHT_PROGBITS
sh_flags 0x00000006 SHF_ALLOC | SHF_EXECINSTR
sh_addr 0x00000000004000b0 Virtual address of section in memory
sh_offset 0x00000000000000b0 Offset of section in file image
sh_size 0x0000000000000025 Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000010 Alignment (2B)
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 2 (.data)
|00000190: 2100 0000 0100 0000 0300 0000 0000 0000| !...............
|000001a0: d800 6000 0000 0000 d800 0000 0000 0000| ..`.............
|000001b0: 0e00 0000 0000 0000 0000 0000 0000 0000| ................
|000001c0: 0400 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x00000021 Offset into .shstrtab
sh_type 0x00000001 SHT_PROGBITS
sh_flags 0x0000000000000003 SHF_WRITE | SHF_ALLOC
sh_addr 0x00000000006000d8 Virtual address of section in memory
sh_offset 0x00000000000000d8 Offset of section in file image
sh_size 0x000000000000000e Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000004 Alignment (4B)
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 3 (.shstrtab)
|000001d0: 1100 0000 0300 0000 0000 0000 0000 0000| ................
|000001e0: 0000 0000 0000 0000 e600 0000 0000 0000| ................
|000001f0: 2700 0000 0000 0000 0000 0000 0000 0000| '...............
|00000200: 0100 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x00000011 Offset into .shstrtab
sh_type 0x00000003 SHT_STRTAB
sh_flags 0x00000000 No flags
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x00000000000000e6 Offset of section in file image
sh_size 0x0000000000000027 Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extra info about section
sh_addralign 0x0000000000000001 Alignment (1B)
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section header table: Entry 4 (.symtab)
|00000210: 0100 0000 0200 0000 0000 0000 0000 0000| ................
|00000220: 0000 0000 0000 0000 9002 0000 0000 0000| ................
|00000230: f000 0000 0000 0000 0500 0000 0600 0000| ................
|00000240: 0800 0000 0000 0000 1800 0000 0000 0000| ................
sh_name 0x00000001 Offset into .shstrtab
sh_type 0x00000002 SHT_SYMTAB
sh_flags 0x00000000 No flags
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000290 Offset of section in file image
sh_size 0x00000000000000f0 Size in bytes of section in file image
sh_link 0x00000005 Section index of associated section
sh_info 0x00000006 Flags
sh_addralign 0x0000000000000008 Alignment (8B)
sh_entsize 0x0000000000000018 Size in bytes of each entry (24B)
Section header table: Entry 5 (.strtab)
|00000250: 0900 0000 0300 0000 0000 0000 0000 0000| ................
|00000260: 0000 0000 0000 0000 8003 0000 0000 0000| ................
|00000270: 3700 0000 0000 0000 0000 0000 0000 0000| 7...............
|00000280: 0100 0000 0000 0000 0000 0000 0000 0000| ................
sh_name 0x00000009 Offset into .shstrtab
sh_type 0x00000003 SHT_STRTAB
sh_flags 0x0000000000000000 No flags
sh_addr 0x0000000000000000 Virtual address of section in memory
sh_offset 0x0000000000000380 Offset of section in file image
sh_size 0x0000000000000037 Size in bytes of section in file image
sh_link 0x00000000 Section index of associated section
sh_info 0x00000000 Extrac info about section
sh_addralign 0x0000000000000001 Alignment (1B)
sh_entsize 0x0000000000000000 Size in bytes of each entry
Section 4: .symtab (SHT_SYMTAB;)
Symbol table entry 0
|00000290: 0000 0000 0000 0000 0000 0000 0000 0000| ................
|000002a0: 0000 0000 0000 0000 | ........
st_name 0x00000000
st_info 0x00
st_other 0x00
st_shndx 0x0000 (SHN_UNDEF)
st_value 0x0000000000000000
st_size 0x0000000000000000
Symbol table entry 1
|000002a8: 0000 0000 0300 0100| ........
|000002b0: b000 4000 0000 0000 0000 0000 0000 0000| ..@.............
st_name 0x00000000
st_info 0x03 (STT_OBJECT | STT_FUNC)
st_other 0x00
st_shndx 0x0001 (Section 1: .text)
st_value 0x00000000004000b0
st_size 0x0000000000000000
Symbol table entry 2
|000002c0: 0000 0000 0300 0200 d800 6000 0000 0000| ..........`.....
|000002d0: 0000 0000 0000 0000 | ........
st_name 0x00000000
st_info 0x03 (STT_OBJECT | STT_FUNC)
st_other 0x00
st_shndx 0x0002 (Section 2: .data)
st_value 0x00000000006000d8
st_size 0x0000000000000000
Symbol table entry 3 (hello.asm)
|000002d0: 0100 0000 0400 f1ff| ........
|000002e0: 0000 0000 0000 0000 0000 0000 0000 0000| ................
st_name 0x00000001
st_info 0x04 (STT_FILE)
st_other 0x00
st_shndx 0xfff1 (SHN_ABS)
st_value 0x0000000000000000
st_size 0x0000000000000000
Symbol table entry 4 (hello)
|000002f0: 0b00 0000 0000 0200 d800 6000 0000 0000| ..........`.....
|00000300: 0000 0000 0000 0000 | ................
st_name 0x0000000b
st_info 0x00
st_other 0x00
st_shndx 0x0002 (Section 2: .data)
st_value 0x00000000006000d8
st_size 0x0000000000000000
Symbol table entry 5 (hbytes)
|00000300: 1100 0000 0000 f1ff| ........
|00000310: 0e00 0000 0000 0000 0000 0000 0000 0000| ................
st_name 0x00000011
st_info 0x00
st_other 0x00
st_shndx 0xfff1 (SHN_ABS)
st_value 0x000000000000000e
st_size 0x0000000000000000
Symbol table entry 6 (_start)
|00000320: 1800 0000 1000 0100 b000 4000 0000 0000| ..........@.....
|00000330: 0000 0000 0000 0000 | ........
st_name 0x00000018
st_info 0x10 (STB_GLOBAL)
st_other 0x00
st_shndx 0x0001 (Section 1: .text)
st_value 0x00000000004000b0
st_size 0x0000000000000000
Symbol table entry 7 (__bss_start)
|00000330: 1f00 0000 1000 f1ff| ........
|00000340: e600 6000 0000 0000 0000 0000 0000 0000| ..`.............
st_name 0x0000001f
st_info 0x10 (STB_GLOBAL)
st_other 0x00
st_shndx 0xfff1 (SHN_ABS)
st_value 0x00000000006000e6
st_size 0x0000000000000000
Symbol table entry 8 (_edata)
|00000350: 2b00 0000 1000 f1ff e600 6000 0000 0000| +.........`.....
|00000360: 0000 0000 0000 0000 | ........
st_name 0x0000002b
st_info 0x10 (STB_GLOBAL)
st_other 0x00
st_shndx 0xfff1 (SHN_ABS)
st_value 0x00000000006000e6
st_size 0x0000000000000000
Symbol table entry 9 (_end)
|00000360: 3200 0000 1000 f1ff| 2.......
|00000370: e800 6000 0000 0000 0000 0000 0000 0000| ..`.............
st_name 0x00000032
st_info 0x10 (STB_GLOBAL)
st_other 0x00
st_shndx 0xfff1 (SHN_ABS)
st_value 0x00000000006000e8
st_size 0x0000000000000000
Section 6: .strtab (SHT_STRTAB;)
|00000380: 0068 656c 6c6f 2e61 736d 0068 656c 6c6f| .hello.asm.hello
|00000390: 0068 6279 7465 7300 5f73 7461 7274 005f| .hbytes._start._
|000003a0: 5f62 7373 5f73 7461 7274 005f 6564 6174| _bss_start._edat
|000003b0: 6100 5f65 6e64 00 | a._end.
0x00000000: ''
0x00000001: 'hello.asm'
0x0000000b: 'hello'
0x00000011: 'hbytes'
0x00000018: '_start'
0x0000001f: '__bss_start'
0x0000002b: '_edata'
0x00000032: '_end'
Effect of stripping
Running strip
on the binary has the effect of dropping the .symtab
and
.strtab
sections along with their section headers and 16 bytes of data (the
section names .symtab
and .strtab
) from the .shstrtab
section, reducing the
total binary size to 512 bytes.
In-memory process image
FreeBSD uses a memory superpage size of 2MB (page size of 4kB) on x86_64. Since
attributes are set at the page level, read+execute program .text
and
read+write .data
are loaded into two separate segments on separate pages, as
laid-out by the linker.
On launch, the kernel maps the binary image into memory as specified in the program header table:
- PHT Entry 0: The ELF header, program header table, and Section 1 (
.text
) are mapped from offset 0x00 of the binary image (with length 0xd6 bytes) into Segment 1 (readable, executable) at address 0x400000. - PHT Entry 1: Section 2 (
.data
) at offset 0xd8 of the binary image is mapped into Segment 2 (readable, writeable) at address 0x6000d8 from offset 0xd8 with length 0x0e bytes.
The program entrypoint is specified to be 0x4000b0, the start of the .text
section.
And that’s it! Any corrections or comments are always welcome. Shoot me an email at chris@bracken.jp.