如何理解ELF程序头中Offset和VirAddr之间的区别?

3

有一个共享库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?它们总是相同的吗?在动态加载过程中会发生改变吗?

p_offset - 文件中的偏移量,p_vaddr - 段在加载到内存后的地址(例如,在 C 运行时初始化之后)。 - izac89
2个回答

4
如何理解readelf -l输出中对应偏移量(Offset)和虚拟地址(VirtAddr)的p_offset和p_vaddr之间的区别?
运行时加载器将在虚拟地址.p_vaddr(向下舍入;对于ET_DYN对象,该地址实际上会添加一些大的多页偏移量)处的偏移量.p_offset(向下舍入到页面大小)映射一组页面。
它们总是相同的吗?
即使在你的例子中,它们也不是相同的:
LOAD           0x3ab1cc 0x003ac1cc

0x3ab1 不等于 0x3ac1。保证的是.p_offset % pagesize == .p_vaddr % pagesize(否则将无法使用mmap)。


3

一般来说-

p_offset - elf文件内的偏移量

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

它们不总是相同的,这些地址可以使用链接器脚本进行配置。请参考此文档

至于共享库加载到进程地址空间后的地址-这取决于进程地址空间、ASLR等等,但可以肯定的是动态加载程序会设置新的地址(p_vaddr,也称为执行地址)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接