How to understand the difference between Offset and VirAddr in Program Headers in elf?

2

There is a shared library elf file, I use readelf -l to see the program headers, the output is:

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 

if the following struct represents an program header:

   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;

Then my question is: How to understand the difference between p_offset and p_vaddr which corresponds to Offset and VirtAddr in output of readelf -l? Will them always be the same? And will them be changed by the procedure of dynamic loading?

elf
dynamic-linking
dynamic-loading
readelf
asked on Stack Overflow Sep 27, 2018 by cong

2 Answers

3

Generally speaking-

p_offset - offset within the elf file

p_vaddr - address of section after loaded to memory (say, after c runtime initialization finished)

They will not always be the same, those addresses can be configured using linker script for example. Refer to this.

As for the shared library addresses after library loaded into a process address space - this depends on process addresses space, ASLR, and more, but its safe to say that the dynamic loader will set new addresses (p_vaddr, aka execution address)

answered on Stack Overflow Sep 27, 2018 by user2162550 • edited Jun 20, 2020 by Community
2

How to understand the difference between p_offset and p_vaddr which corresponds to Offset and VirtAddr in output of readelf -l?

The runtime loader will mmap a set of pages at offset .p_offset (rounded down to pagesize) at virtual address .p_vaddr (similarly rounded down; that address will actually have some large multiple-page offset added to it for ET_DYN object).

Will them always be the same?

They aren't the same even in your example:

LOAD           0x3ab1cc 0x003ac1cc

0x3ab1 != 0x3ac1. What is guaranteed is that .p_offset % pagesize == .p_vaddr % pagesize (otherwise mmap will become impossible).

answered on Stack Overflow Sep 28, 2018 by Employed Russian • edited Sep 28, 2018 by Employed Russian

User contributions licensed under CC BY-SA 3.0