ELF程序头段大小和偏移量 [英] ELF program header segments sizes and offsets

查看:42
本文介绍了ELF程序头段大小和偏移量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试理解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;
}

WITHg++ -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

使用无福祸不单行编辑器我正在查看代码,并尝试找到这些段中的每一个。

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

  • 我找到声明解释器的片段,就在PHDR之后。它的大小与解释器的路径相同,对齐方式为1字节。正确

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

    /li>
  • 下一个(可读写)[!]我想是存储变量的段。它的结束位置可能与区段标题类似的位置
  • 现在下一个是动态头。它从0xe18开始,它在上面的那个里面。[!]我认为这是存储对外部函数和变量的引用的段,但我不确定。它是可读写的。我只是不知道这是什么段,为什么它在加载段上面的"内部"
  • 注释片段,包含一些我认为目前并不重要的信息
  • GNU特定的段,其中一个段的偏移量和大小等于0x0000000000000000,其他段干扰其他段,我也不明白。

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

推荐答案

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

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

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

现在我有了一个可读和可执行的段,[!]我 假设是代码段。我不明白为什么一开始是 0x000000000000000000。这不是应该从入口点开始吗 定位了吗?为什么它的大小是0xafc字节?不是只有尺码吗? 代码的大小是多少?文件中有多少是可执行的?另外,我 我不明白为什么对齐是0x200000字节。那是多少钱? 在内存中为加载段保留了空间。这就是这个 段结束,其后跟随764 0x0字节:

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

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

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

现在,下一个是动态标头。从0xe18开始,也就是 在上面的那个里面。[!]我以为这是一段引用 到外部的函数和变量都存储了,但我不确定。它 是可读和可写的。我只是不知道这是什么部分 为什么它在加载段上方的"内部"

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

GNU特定段,其中之一具有相等的偏移量和大小 设置为0x0000000000000000,其他干扰其他网段,即 也不要得到。

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

引用:

  1. ELF File format specification
  2. 链接器和加载器,约翰·R·莱文著

这篇关于ELF程序头段大小和偏移量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆