如何理解 elf 中程序标头中的偏移量和 VirAddr 之间的区别?



有一个共享库elf文件,我用readelf -l看程序头,输出是:

Elf file type is DYN (Shared object file)
Entry point 0x0
There are 11 program headers, starting at offset 52
Program Headers:
Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
PHDR           0x000034 0x00000034 0x00000034 0x00100 0x00100 R   0x4
INTERP         0x000194 0x00000194 0x00000194 0x00013 0x00013 R   0x1
[Requesting program interpreter: /system/bin/linker]
LOAD           0x000000 0x00000000 0x00000000 0x3aa8c4 0x3aa8c4 R E 0x1000
LOAD           0x3ab1cc 0x003ac1cc 0x003ac1cc 0x062c0 0x25ee4 RW  0x1000
LOAD           0x3b2000 0x003d3000 0x003d3000 0x02561 0x02561 R E 0x1000
LOAD           0x3b4e8c 0x003d6e8c 0x003d6e8c 0x00298 0x00299 RW  0x1000
LOAD           0x3b5268 0x003d8268 0x003d8268 0x00128 0x00128 RW  0x1000
DYNAMIC        0x3b5268 0x003d8268 0x003d8268 0x00128 0x00128 RW  0x4
GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0
EXIDX          0x2e71e8 0x002e71e8 0x002e71e8 0x0b558 0x0b558 R   0x4
GNU_RELRO      0x3ab1cc 0x003ac1cc 0x003ac1cc 0x01e34 0x01e34 RW  0x4
Section to Segment mapping:
Segment Sections...
00     
01     .interp 
02     .interp .dynsym .dynstr .hash .gnu.version .gnu.version_d .rel.dyn .plt .text .ARM.extab .ARM.exidx .rodata 
03     .data.rel.ro.local .fini_array .data.rel.ro .got .data .bss 
04     .rel.plt 
05     .init_array 
06     .dynamic 
07     .dynamic 
08     
09     .ARM.exidx 
10     .data.rel.ro.local .fini_array .data.rel.ro .got 

如果以下结构表示程序标头:

typedef struct {
uint32_t   p_type;
Elf32_Off  p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
uint32_t   p_filesz;
uint32_t   p_memsz;
uint32_t   p_flags;
uint32_t   p_align;
} Elf32_Phdr;

那么我的问题是:如何理解p_offsetp_vaddr之间的区别,对应于readelf -l输出中的OffsetVirtAddr?它们会永远一样吗?它们会被动态加载程序改变吗?

如何理解 readelf -l 输出中对应于偏移量和 VirtAddr 的 p_offset 和 p_vaddr 之间的区别?

运行时加载程序将在虚拟地址.p_vaddr处以偏移量.p_offset(向下舍入为 pagesize(mmap一组页面(类似地向下舍入;该地址实际上会为ET_DYN对象添加一些大的多页偏移量(。

它们会永远一样吗?

即使在您的示例中,它们也不相同:

LOAD           0x3ab1cc 0x003ac1cc

0x3ab1!=0x3ac1.可以保证的是.p_offset % pagesize == .p_vaddr % pagesize(否则mmap将变得不可能(。

一般来说-

p_offset- elf 文件中的偏移量

p_vaddr- 加载到内存后(例如,在 C 运行时初始化完成后(的部分地址

它们并不总是相同的,例如,可以使用链接器脚本配置这些地址。请参阅此处。

至于库加载到进程地址空间后的共享库地址 - 这取决于进程地址空间、ASLR 等,但可以肯定地说,动态加载程序将设置新地址(p_vaddr,又名执行地址(

最新更新