Reputation: 112
I'm generating an Elf executable file. I am encountering a problem I don't understand. I've been able to reproduce the problem with a small nasm file:
bits 64
va equ 0x1000
elf_header:
db 0x7F, "ELF", 2, 1, 1, 0 ; e_ident
times 8 db 0 ; unused padding
dw 2 ; e_type
dw 62 ; e_machine
dd 1 ; e_version
dq va + 0x40 + 0x38 ; e_entry
dq 0x40 ; e_phoff
dq 0 ; e_shoff
dd 0 ; e_flags
dw 0x40 ; e_ehsize
dw 0x38 ; e_phentsize
dw 1 ; e_phnum
dw 0x40 ; e_shentsize
dw 0 ; e_shnum
dw 0 ; e_shstrndx
program_header:
dd 1 ; p_type
dd 7 ; p_flags
dq _start ; p_offset
dq va + _start ; p_vaddr
dq va + _start ; p_paddr
dq _start_end - _start ; p_filesz
dq _start_end - _start ; p_memsz
dq 0x1000 ; p_align
_start:
mov edi, 42
mov eax, 60
syscall
_start_end:
As you can see, there is a single program header pointing to a single tiny segment _start
. Reading this file, it seems okay:
$ nasm -f bin -o test test.asm
$ objdump --all-headers test
debug: file format elf64-x86-64
architecture: x86_64
start address: 0x0000000000001078
Program Header:
LOAD off 0x0000000000000078 vaddr 0x0000000000001078 paddr 0x0000000000001078 align 2**12
filesz 0x000000000000000c memsz 0x000000000000000c flags rwx
Dynamic Section:
Sections:
Idx Name Size VMA Type
0 PT_LOAD#0 0000000c 0000000000001078 TEXT
SYMBOL TABLE:
The rule offset % alignment == vaddr % aligment
is respected as far as I understand it.
However, when I try to run this program, I get the following error:
$ ./test
assertion failed [segment_file_size >= size_of_elf_and_program_headers]: first load segment does not span the elf header size
I see in multiple places on Internet that it is NOT mandatory for the first load segment to include the elf header, along with the program header, but this failing assertion seems to tell the opposite.
However, I can trick this by changing _start
to add empty instructions (nop
) in order to increase the segment size:
_start:
times 150 nop
mov edi, 42
mov eax, 60
syscall
_start_end:
This time, it executes nicely:
$ nasm -f bin -o test test.asm
$ objdump --all-headers test
debug: file format elf64-x86-64
architecture: x86_64
start address: 0x0000000000001078
Program Header:
LOAD off 0x0000000000000078 vaddr 0x0000000000001078 paddr 0x0000000000001078 align 2**12
filesz 0x00000000000000a2 memsz 0x00000000000000a2 flags rwx
Dynamic Section:
Sections:
Idx Name Size VMA Type
0 PT_LOAD#0 000000a2 0000000000001078 TEXT
SYMBOL TABLE:
$ ./test
$ echo $?
42
Another alternative would effectively to use set offset = 0
, and move the offset onto vaddr
, like so (diff based on the first version with the initial _start
):
--- test.asm 2024-11-12 10:03:40
+++ offset_eq_0.asm 2024-11-12 10:03:48
@@ -22,11 +22,11 @@
program_header:
dd 1 ; p_type
dd 7 ; p_flags
- dq _start ; p_offset
- dq va + _start ; p_vaddr
- dq va + _start ; p_paddr
- dq _start_end - _start ; p_filesz
- dq _start_end - _start ; p_memsz
+ dq 0 ; p_offset
+ dq va ; p_vaddr
+ dq va ; p_paddr
+ dq _start_end - _start + 0x40 + 0x38 ; p_filesz
+ dq _start_end - _start + 0x40 + 0x38 ; p_memsz
dq 0x1000 ; p_align
_start:
The entry point is still set at va + 0x40 + 0x38
, which is valid. And this time, it works:
$ ./offset_eq_0
$ echo $?
42
In this version, the p_filesz
and p_memsz
are larger than the size of the Elf header too.
I'm generating this file from aarch64 macOS, but I'm running on a x86_64 Debian machine (Linux debian 6.11.5-orbstack-00280-g96d99c92a42b #51 SMP Sun Nov 3 08:07:37 UTC 2024 x86_64 GNU/Linux
) via OrbStack.
Nowhere on Internet I'm able to find this error, any source code repositories, archives, nothing, nowhere.
Upvotes: 4
Views: 86