【问题标题】:which part of ELF file must be loaded into the memory?必须将 ELF 文件的哪一部分加载到内存中?
【发布时间】:2012-05-12 03:18:19
【问题描述】:

可执行文件的ELF文件有一个程序(段)头和一个节头,可以通过readelf -a看到,下面是一个例子:

上面两张图分别是section header和program(segment) header。可以看出,一个段头是由几个段头组成的,用于将程序加载到内存中。

是否只需要将 .text、.rodata、.data、.bss 段加载到内存中?

段中的所有其他部分(例如,第 3 段中的 .ctors、.dtors .jcr)是否都用于对齐?

【问题讨论】:

  • @Adriano,是的,与页面大小对齐,因此可以对程序的不同部分使用不同的保护,例如 .text(r-x),.data(rw-)

标签: c linux memory elf


【解决方案1】:

节和段是完全不同的两个概念。部分与存储在那里的数据的语义有关(即它将用于什么),并且一旦链接程序或共享库,除了调试目的之外实际上是无关紧要的。您甚至可以完全删除节标题(或用随机垃圾覆盖它们)并且程序仍然可以工作。

段(即程序头加载指令)是内核和/或动态链接器在加载程序时实际查看的内容。例如,在您的情况下,您有两个加载指令。第一个导致文件的前 4k(1 页)映射到地址 0x08048000,并表示实际上只使用此映射的前 0x4b8 个字节(其余为对齐)。第二个导致文件的前 8k(2 页)映射到地址 0x08049000。其中绝大多数是对齐。前 0xf14 字节不是加载指令的一部分(只是对齐),将被浪费。从 0x08049f14 开始,实际使用从文件映射的 0x108 字节,另外 0x10 字节(以达到 0x118 的 MemSize)由加载器(内核或动态链接器)填充零。这最多跨越 0x0804a02c(在第二个映射页面中)。第二个映射页面的其余部分未使用/浪费(但malloc 可能能够恢复它以用作堆的一部分)。

最后,虽然根本不会使用节标题,但您的程序在运行时可能会使用许多不同节的内容。注意.ctors.dtors的地址范围位于第二个加载映射的开头,因此它们在运行时被程序映射和访问(运行时启动/退出代码将使用它们来运行全局构造函数和析构函数,如果使用了具有 ctor/dtor 属性的 C++ 或“GNU C”代码)。另请注意,.data 开始于地址 0x0804a00c,在第二个映射页面中。这允许在应用重定位后以只读方式保护第一页(程序头中的 RELRO 指令)。

【讨论】:

  • C 有像 C++ 一样的构造函数或析构函数吗?
  • 不,但是 GCC 不是 C,它是“GNU C”。你可以做各种非标准的东西,比如异常和构造函数。
  • @R..: 所以,.data 段地址从p_vaddrp_filesiz.bssp_addr + p_filesizp_memsiz 然后是第二个所有负载的大小是p_memsiz - p_vaddr 吗?
  • @Soumen:页面大小是特定于架构的 ABI 或运行时约束;对于 x86_64,它是 4k 的倍数,实际上它始终是 4k。由于段的长度超过了从开始 (0xf14 mod 4k) 到下一个 4k 边界的距离,因此在 4k 页面大小下需要 2 个页面。
  • @Soumen:我想我可能说得不好。它更像是打包而不是对齐,这是一种权衡,可以节省少量(逻辑的,甚至可能不是真实的)磁盘空间,以换取在运行时浪费额外的页面。前 0xf14 字节是 ELF 标头和第一个(只读)加载段的内容。如果链接器一直等到偏移量 0x1000 才开始第二个加载映射,那么它都可以放在一个页面中。
猜你喜欢
  • 1970-01-01
  • 2017-01-22
  • 1970-01-01
  • 2010-11-08
  • 1970-01-01
  • 2017-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多