我正在構建一個 RISC-V 模擬器,它基本上將整個 ELF 檔案加載到記憶體中。
到目前為止,我使用的是 risc-v 基礎提供的預編譯的測驗二進制檔案,它在本.text節的開頭很方便地有一個入口點。
例如:
> riscv32-unknown-elf-objdump ../riscv32i-emulator/tests/simple -d
../riscv32i-emulator/tests/simple: file format elf32-littleriscv
Disassembly of section .text.init:
80000000 <_start>:
80000000: 0480006f j 80000048 <reset_vector>
...
進入這個專案時,我對 ELF 檔案了解不多,所以我只是假設每個 ELF 的入口點與本節的開頭完全相同.text。
當我編譯自己的二進制檔案時出現了問題,我發現實際的入口點并不總是與.text節的開頭相同,但它可能在其中的任何地方,就像這里:
> riscv32-unknown-elf-objdump a.out -d
a.out: file format elf32-littleriscv
Disassembly of section .text:
00010074 <register_fini>:
10074: 00000793 li a5,0
10078: 00078863 beqz a5,10088 <register_fini 0x14>
1007c: 00010537 lui a0,0x10
10080: 43850513 addi a0,a0,1080 # 10438 <__libc_fini_array>
10084: 3a00006f j 10424 <atexit>
10088: 00008067 ret
0001008c <_start>:
1008c: 00002197 auipc gp,0x2
10090: cec18193 addi gp,gp,-788 # 11d78 <__global_pointer$>
...
因此,在閱讀了有關 ELF 檔案的更多資訊后,我發現實際的入口點地址是由EntryELF 標頭上的條目提供的:
> riscv32-unknown-elf-readelf a.out -h | grep Entry
Entry point address: 0x1008c
The problem now becomes that this address is not the actual address on the file (offset from 0) but is a virtual address, so obviously if I set the program counter of my emulator to this address, the emulator would crash.
Reading a bit more, I heard people talk about calculations regarding offsets from program headers and whatnot, but no one had a concrete answer.
My question is: what is the actual "formula" of how exactly you get the entry point address of the _start procedure as an offset from byte 0?
Just to be clear my emulator doesn't support virtual memory and the binary is the only thing that is loaded into my emulator's memory, so I have no use for the abstraction of virtual memory. I just want every memory address as physical address on disk.
uj5u.com熱心網友回復:
我的問題是:您如何準確地將 _start 程序的入口點地址作為從位元組 0 的偏移量獲取的實際“公式”是什么?
首先,忘記section。只有段 在運行時才重要。
其次,用于readelf -Wl查看細分市場。它們準確地告訴您哪個檔案塊 ( [.p_offset, .p_offset .p_filesz)) 進入了哪個記憶體區域 ( [.p_vaddr, .p_vaddr .p_memsz))。
“檔案中確實存在的偏移量”的精確計算_start是:
- 找出
Elf32_Phdr哪些“覆寫”了 中包含的地址Elf32_Ehdr.e_entry。 - 使用那個
phdr,檔案偏移量_start是:ehdr->e_entry - phdr->p_vaddr phdr->p_offset.
更新:
那么,我是否一直在尋找第一個程式頭?
不。
同樣,“覆寫”是指第一個 phdr->p_vaddr 總是等于 e_entry?
不。
您正在尋找與記憶體重疊的程式頭(描述記憶體和檔案資料之間的關系)ehdr->e_entry。也就是說,您正在尋找phdr->p_vaddr <= ehdr->e_entry && ehdr->e_entry < phdr->p_vaddr phdr->p_memsz. 這部分通常是第一個,但這絕不能保證。另請參閱此答案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/439005.html
