ELF 程序头和虚拟地址

ELF Program Headers and Virtual Address

我了解 ELF 及其程序头。当我使用 readelf 读取文件类型为 DYN 的 ELF 时。我在程序头中看到虚拟地址值实际上来自内核虚拟地址 space.

Elf file type is DYN (Shared object file)
Entry point 0x1060
There are 13 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R      0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000600 0x0000000000000600  R      0x1000
  LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                 0x00000000000001f5 0x00000000000001f5  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
                 0x0000000000000168 0x0000000000000168  R      0x1000
  LOAD           0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
                 0x0000000000000258 0x0000000000000260  RW     0x1000
  DYNAMIC        0x0000000000002dc8 0x0000000000003dc8 0x0000000000003dc8
                 0x00000000000001f0 0x00000000000001f0  RW     0x8
  NOTE           0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000020 0x0000000000000020  R      0x8
  NOTE           0x0000000000000358 0x0000000000000358 0x0000000000000358
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_PROPERTY   0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000020 0x0000000000000020  R      0x8
  GNU_EH_FRAME   0x0000000000002018 0x0000000000002018 0x0000000000002018
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
                 0x0000000000000248 0x0000000000000248  R      0x1

我能够推断出加载二进制文件时实际的 VirtAddr 应该是 = 基地址 + VirtAddr。但是我无法找出加载程序如何计算基址值?

此外,我知道 .text 和 .data 是用于加载二进制文件的两个 PT_LOAD 段。但是我在示例中看到了 4 PT_LOAD 个程序头。两个 PT_LOAD 程序头有什么用?

这是不是具有设置基地址的程序。相反,它是一个 position-independent 可执行文件,可以链接到内存中的 任何 地址,从而启用地址 space 布局随机化,即 ALSR。

它与普通共享库的区别在于它有程序解释器集,一般共享库没有...

这里的最低虚拟内存地址正好是0x0000000000000040,对应文件偏移量0x0000000000000040.

I see virtual address value in Program Headers is actually from kernel Virtual address space.

不,你看到。 None 输出中的地址与内核有关。

您正在查看的是一个Position Independent executable,它可以加载到内存中任何地方

I'm not able to find out how loader calculates the Base Address Value?

加载器不加载主可执行文件(内核加载),也不决定加载地址。

鉴于文件类型是ET_DYN,内核执行相当于 mmap(0, ...)(没有 MAP_FIXED 标志),并选择一个合适的虚拟地址,然后将其传送给 aux 向量中的加载程序。

But I see 4 PT_LOAD program headers in my example. What are two PT_LOAD program headers used for?

参见 答案。