如何理解elf中Program Headers中Offset和VirAddr的区别?
How to understand the difference between Offset and VirAddr in Program Headers in 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
之间的区别,分别对应readelf -l
输出的Offset
和VirtAddr
?他们会永远一样吗?动态加载的过程会改变它们吗?
一般来说-
p_offset
- elf 文件中的偏移量
p_vaddr
- 加载到内存后的段地址(比如,在 c 运行时初始化完成后)
它们并不总是相同的,例如,可以使用链接描述文件配置这些地址。 Refer to this.
至于库加载到进程地址后的共享库地址space - 这取决于进程地址space、ASLR 等,但可以肯定地说动态加载程序将设置新地址(p_vaddr
,又名执行地址)
How to understand the difference between p_offset and p_vaddr which corresponds to Offset and VirtAddr in output of readelf -l?
运行时加载程序将 mmap
一组位于虚拟地址 .p_vaddr
偏移量 .p_offset
处的页面(向下舍入为页面大小)(类似向下舍入;该地址实际上有一些为 ET_DYN
对象添加了大的多页偏移量)。
Will them always be the same?
即使在您的示例中,它们也不相同:
LOAD 0x3ab1cc 0x003ac1cc
0x3ab1
!= 0x3ac1
。 是保证的是.p_offset % pagesize == .p_vaddr % pagesize
(否则mmap
就不可能了)
有个共享库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
之间的区别,分别对应readelf -l
输出的Offset
和VirtAddr
?他们会永远一样吗?动态加载的过程会改变它们吗?
一般来说-
p_offset
- elf 文件中的偏移量
p_vaddr
- 加载到内存后的段地址(比如,在 c 运行时初始化完成后)
它们并不总是相同的,例如,可以使用链接描述文件配置这些地址。 Refer to this.
至于库加载到进程地址后的共享库地址space - 这取决于进程地址space、ASLR 等,但可以肯定地说动态加载程序将设置新地址(p_vaddr
,又名执行地址)
How to understand the difference between p_offset and p_vaddr which corresponds to Offset and VirtAddr in output of readelf -l?
运行时加载程序将 mmap
一组位于虚拟地址 .p_vaddr
偏移量 .p_offset
处的页面(向下舍入为页面大小)(类似向下舍入;该地址实际上有一些为 ET_DYN
对象添加了大的多页偏移量)。
Will them always be the same?
即使在您的示例中,它们也不相同:
LOAD 0x3ab1cc 0x003ac1cc
0x3ab1
!= 0x3ac1
。 是保证的是.p_offset % pagesize == .p_vaddr % pagesize
(否则mmap
就不可能了)