ELF程序标题段大小和偏移量

时间:2014-02-20 10:40:08

标签: header size offset elf segment

我正在尝试理解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 我正在查看代码并尝试找到这些段中的每一个。

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

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

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

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

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

1 个答案:

答案 0 :(得分:7)

readelf输出显示程序头表。它包含ELF文件中的段列表(可以是可加载的或不可加载的)。如图所示,段通常包含其他段。

  

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

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

  

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

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

  

下一个(可读和可写)[!]我想是一个片段在哪里   变量存储。它结束就像部分之类的东西   标题可能正在开始。

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

  

现在下一个是DYNAMIC标题。它从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. Linkers and Loaders,作者:John R. Levine