【问题标题】:ELF Program Headers and Virtual AddressELF 程序头和虚拟地址
【发布时间】:2020-11-28 18:39:38
【问题描述】:

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

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 程序头是干什么用的?

【问题讨论】:

  • 我实际上只从这个页面得到了基地址的想法。它说“可执行和共享目标文件有一个基地址,它是与程序目标文件的内存映像相关联的最低虚拟地址。基地址的一种用途是在动态链接期间重新定位程序的内存映像。”但我仍然不知道如何找到最低的虚拟地址?

标签: c executable elf dynamic-linking readelf


【解决方案1】:

不是一个设置了基地址的程序。相反,它是一个与位置无关的可执行文件,可以链接到内存中的任何地址,从而实现地址空间布局随机化,即 ALSR。

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

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

【讨论】:

    【解决方案2】:

    我看到 Program Headers 中的虚拟地址值实际上来自内核虚拟地址空间。

    不,你没有看到。输出中的所有地址都与内核无关。

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

    我不知道加载器如何计算基地址值?

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

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

    但我在示例中看到了 4 个 PT_LOAD 程序头。两个 PT_LOAD 程序头是干什么用的?

    请参阅this 答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 2011-09-07
      • 1970-01-01
      • 2011-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多