Hand-decoding an ELF binary image

31 October 2018

While 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)

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:

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.