Как понять разницу между Offset и VirAddr в заголовках программ в elf?

Существует общий файл библиотеки 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_offset и p_vaddr, которая соответствует Offset и VirtAddr в выводе readelf -l? Всегда ли они будут одинаковыми? И будут ли они изменены процедурой динамической загрузки?


person cong    schedule 27.09.2018    source источник
comment
p_offset - смещение в файле, p_vaddr - адрес секции после загрузки в память (скажем, после инициализации среды выполнения c)   -  person user2162550    schedule 27.09.2018


Ответы (2)


Вообще говоря-

p_offset - смещение внутри файла elf

p_vaddr - адрес секции после загрузки в память (скажем, после завершения инициализации среды выполнения c)

Они не всегда будут одинаковыми, эти адреса можно настроить, например, с помощью скрипта компоновщика. см. здесь.

Что касается адресов разделяемой библиотеки после загрузки библиотеки в адресное пространство процесса — это зависит от пространства адресов процесса, ASLR и т. д., но можно с уверенностью сказать, что динамический загрузчик установит новые адреса (p_vaddr, он же адрес выполнения)

person user2162550    schedule 27.09.2018

Как понять разницу между p_offset и p_vaddr, которая соответствует Offset и VirtAddr в выводе readelf -l?

Загрузчик среды выполнения будет mmap набором страниц со смещением .p_offset (округленным в меньшую сторону до размера страницы) по виртуальному адресу .p_vaddr (аналогично округленному в меньшую сторону; на самом деле к этому адресу будет добавлено большое многостраничное смещение для объекта ET_DYN).

Всегда ли они будут одинаковыми?

Они различны даже в вашем примере:

LOAD           0x3ab1cc 0x003ac1cc

0x3ab1 != 0x3ac1. Что гарантировано, так это то, что .p_offset % pagesize == .p_vaddr % pagesize (иначе mmap станет невозможным).

person Employed Russian    schedule 28.09.2018