【问题标题】:ELF program header segments sizes and offsetsELF 程序头段大小和偏移量
【发布时间】:2014-03-21 05:51:51
【问题描述】:

我正在尝试理解 ELF 格式,但现在对于程序头中定义的段,有些事情我不明白。我有这个小代码,我用 g++(Linux 上的 x86_x64)转换为 ELF 文件:

#include <stdlib.h>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    if (argc == 1)
    {
        cout << "Hello world!" << endl;
    }
    return 0;
}

使用g++ -c -m64 -D ACIS64 main.cpp -o main.og++ -s -O1 -o Main main.o。 现在,通过 readelf 我得到了这个片段列表:

Program Headers:
Type           Offset             VirtAddr           PhysAddr
               FileSiz            MemSiz             Flags      Align
PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
               0x00000000000001f8 0x00000000000001f8 R E        8
INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
               0x000000000000001c 0x000000000000001c R          1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
               0x0000000000000afc 0x0000000000000afc R E        200000
LOAD           0x0000000000000df8 0x0000000000600df8 0x0000000000600df8
               0x0000000000000270 0x00000000000003a0 RW         200000
DYNAMIC        0x0000000000000e18 0x0000000000600e18 0x0000000000600e18
               0x00000000000001e0 0x00000000000001e0 RW         8
NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
               0x0000000000000044 0x0000000000000044 R          4
GNU_EH_FRAME   0x00000000000009a4 0x00000000004009a4 0x00000000004009a4
               0x0000000000000044 0x0000000000000044 R          4
GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
               0x0000000000000000 0x0000000000000000 RW         10
GNU_RELRO      0x0000000000000df8 0x0000000000600df8 0x0000000000600df8
               0x0000000000000208 0x0000000000000208 R          1

使用 Bless Hex Editor 我正在查看代码并尝试找到其中的每一个。

  • 我发现 PHDR 段就在 ELF 标头之后,并且具有整个程序标头的大小。它具有 8 个字节的对齐方式,并且是可读/可执行的。 [!]我不明白为什么是可执行文件

  • 我找到了声明解释器的段,就在 PHDR 之后。它具有解释器路径的大小和 1 个字节的对齐方式。正确

  • 现在我有一个可读和可执行的段,[!]我想是代码段。我不明白为什么它从 0x0000000000000000 开始。这不应该从入口点所在的位置开始吗?为什么它的大小为 0xafc 字节?大小不只是代码的大小吗?有多少文件是可执行的?另外,我不明白为什么对齐是 0x200000 字节。那是为内存中的 LOAD 段保留了多少空间?。这是该段结束的地方,后面有 764 个 0x0 字节:

  • 下一个(可读和可写)[!]我想是一个存储变量的段。它在节标题可能开始的地方结束
  • 现在下一个是动态标题。它从 0xe18 开始,在上面的那个里面。 [!]我认为这是一个存储对外部函数和变量的引用的段,但我不确定。它是可读可写的。我只是不知道这是什么段以及为什么它在上面的 LOAD 段“内部”
  • 一个 NOTE 片段,包含一些我认为现在不重要的信息
  • GNU 特定段,其中一个具有任何偏移量和大小等于0x0000000000000000,其他的会干扰其他段,我也不明白。

我来自 PE 世界,每个事物都有自己明确定义的偏移量和大小,在这里我看到这些奇怪的地址和大小,我很困惑。

【问题讨论】:

    标签: header size offset elf segment


    【解决方案1】:

    readelf 输出显示程序头表。它包含 ELF 文件中的段列表(可能是可加载的或不可加载的)。一个段包含其他段是很常见的,如下所示。

    我在 ELF 标头之后找到了 PHDR 段,并且大小为 这整个程序头。它有 8 个字节的对齐,并且是 可读/可执行。 [!]我不明白为什么是可执行文件。

    如果您仔细阅读 readelf 输出,您会注意到 PHDR 实际上是代码段的一部分(请注意 VirtAddr 和 MemSiz 字段)。这就解释了为什么它与代码段 (RX) 共享相同的权限。

    现在我有一个可读和可执行的段,它 [!]I 假设是代码段。我不明白为什么它开始于 0x0000000000000000。这不应该从入口点开始吗 位于?为什么它的大小为 0xafc 字节?不只是大小 代码的大小?有多少文件是可执行的?还有,我 不明白为什么对齐是 0x200000 字节。那是多少 空间是为内存中的 LOAD 段保留的吗?这是这里 段结束,后面有 764 个 0x0 字节:

    是的,这是代码段。它从文件的开头(即偏移量 0)开始,并在文件中扩展到 0xafc 字节。标头指定在加载 ELF 时将文件的这一部分映射到内存中的 0x0000000000400000。该段不仅由 C++ 文件中的 main() 组成,编译器还添加了一些其他可执行文件。对齐只指定下一段应该从哪里开始,而不是段的大小。可加载段应具有以页面大小为模的 VirtAddr 和 PhysAddr 字段(或 Align 字段,如果 Align!=0 && Align!=1)的一致值。这就解释了为什么数据段的 VirtAddr 是 0x0000000000600df8 (0x0000000000600df8 - 0x0000000000000df8 % 0x200000 == 0)。文件中文本段和数据段之间的区域(即 0xafc 和 0xdf8 之间)用零填充。

    下一个(可读和可写)[!]我想是一个片段,其中 变量被存储。它就在类似部分的地方结束 标头可能正在开始。

    正确,这是存储全局变量和静态变量(以及其他内容)的数据段。它在节标题之前结束。

    现在下一个是动态标题。它从 0xe18 开始,即 在上面的那个里面。 [!]我认为这是一个引用的片段 存储到外部函数和变量,但我不确定。它 是可读可写的。我只是不知道这是什么部分 为什么它在上面的 LOAD 段“内部”

    就像 PHDR 段是代码段的一部分一样,DYNAMIC 段是数据段的一部分。这就是为什么相同的权限(RW)。它包含 .dynamic 部分,其中包含结构数组,例如符号和字符串表的地址。

    GNU 特定段,其中一个具有任何偏移量和大小相等 到0x0000000000000000,其他人干扰其他段,我 也不明白。

    GNU_EH_FRAME 是代码段的一部分,GNU_RELRO 是数据段的一部分(参见 VirtAddr 和 MemSiz 字段)。 GNU_STACK 只是一个程序头,它告诉系统在 ELF 加载到内存时如何控制堆栈。 (FileSiz 和 MemSiz 为 0)。

    参考资料:

    1. ELF File format specification
    2. 链接器和加载器,作者:John R. Levine

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-08
      • 1970-01-01
      • 2017-05-03
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      相关资源
      最近更新 更多