我手动编写一个可执行的ELF头+程序头,如下所示:
elf_head:
e_ident db 7Fh, 'ELF', 1, 1, 1
times 9 db 0
e_type dw 2 ; ET_EXEC
e_mach dw 3 ; EM_386
e_ver dd 1 ; EV_CURRENT
e_entry dd 0x08048000+elf_head_len ; entry point
e_phoff dd 34h ; program header table offset
e_shoff dd 00h ; section header table offset
e_flags dd 0 ; flags
e_elfhs dw 34h ; ELF header size
e_phes dw 20h ; program header entry size
e_phec dw 01h ; program header entries count
e_shes dw 00h
e_shec dw 00h
e_shsn dw 00h
elf_ph:
p_type dd 01h ; PT_LOAD
p_off dd elf_head_len
p_vaddr dd 0x08048000+elf_head_len
p_paddr dd 0x08048000+elf_head_len
p_filsz dd elf_head_len+file_len
p_memsz dd elf_head_len+file_len
p_flags dd 7 ; segment flags (RWX)
p_align dd 0x1000 ; page_size==4096bytes
elf_head_len equ $ - elf_head
Run Code Online (Sandbox Code Playgroud)
我在 p_align 字段之后设置了 e_entry 字段点,我将代码放入正在创建的文件中。但这不起作用!我对 p_offset 字段有点困惑。我在那里放置了从文件开头 (0x00) 到段代码的第一个字节的偏移量。由于段的代码在 p_align 字段之后开始,我是否正确输入值 elf_head_len ?当我尝试运行新创建的可执行文件时,bash 响应: 分段错误!
好吧,我发现我的程序有一个错误,导致了分段错误。(对于那个很抱歉)。但问题仍然是关于 p_off 字段,我还发现,如果我设置 p_off dd 0 和 p_vaddr dd 0x08048000 和 p_paddr dd 0x08048000 可执行文件有效。如果我输入 p_off dd elf_head_len 和 p_vaddr dd 0x08048000+elf_head_len 和 p_paddr dd 0x08048000+elf_head_len,它也有效。这让我想起了我在 ELF 格式规范中读到的关于 p_off 和 p_vaddr 值必须一致的内容(也就是说,我认为当对每个值取页面大小的模时,它们必须给出相同的结果)。这就是程序使用这些值的原因。那么现在的问题是:如果上述逻辑有错误请考虑更正。
ELF 规范要求,对于按需分页可执行文件,段的文件偏移量和虚拟地址必须在低位中确实匹配。
这些限制与系统调用对映射施加的限制相同mmap()——它只接受文件中偏移量为页面大小倍数的映射。映射 ELF 文件时,段将扩展到最近的页边界,因此除了段大小计算之外,低位位实际上被忽略。
这样做的一个可能的理由是底层设备可能已经是内存映射的(例如帧缓冲区或闪存),在这种情况下,创建具有未页面对齐的偏移量的映射会产生大量开销。