ELF文件格式

3
我正在尝试将使用g ++编译的elf文件的十六进制转储手动加载到我设计的处理器模拟器中。标准elf文件有30个部分,我正在加载所有30个段,并考虑它们的正确内存位置偏移量。然后,我将程序计数器启动在 .text 部分的开头(00400130),但似乎程序并没有正确运行。我已经相对彻底地使用SPIM作为黄金标准验证了我的处理器设计。奇怪的是,如果我将一个汇编文件加载到SPIM中,然后将软件生成的反汇编的 .text .data 部分提取出来,将它们加载到我的处理器内存中,程序就可以正常运行。这与我的想法不同,因为我想要:
  • 编写c ++程序
  • 使用mipseb-linux-g ++(交叉编译器)进行编译
  • 将所有部分的十六进制转储到各自的文件中
  • 读取文件并将内容加载到处理器的“内存”中
  • 运行程序
在ELF文件中,我应该最初将程序计数器放在哪里?现在我把它放在 .text 的开头。此外,我只需要包含 .text .data ,我的程序才能正常工作吗?我在这里做错了什么?

还有,是否有任何命令可以以与readelf相同的格式转储整个二进制文件(地址0-eof)? - Dan Snyder
1
objcopy -S input output 可以去掉您不需要的所有链接器/调试信息,并生成一个与其输入参数 (input) 格式相同的文件 (output)。 - Aidan Cully
你可能已经做过这个,但如果你还没有,那么你应该验证一下在加载完毕后,你所加载的部分是否包含了你认为应该有的数据。如果你可以在处理器模拟器中查看内存,那么你应该创建一个你的某个部分的二进制表示(objcopy -O binary -j .text input output.bin),并将内存内容与(在这个例子中)output.bin中的数据进行比较。 - Aidan Cully
我已经验证了我的内存映射是否正确。我可以输出每个位置的所有分配内存元素。这似乎很好用。我以同样的方式获取每个部分的偏移量,就像我获取PC起始点一样。 - Dan Snyder
3个回答

5
ELF头应包括入口地址,这不一定与.text区域中的第一个地址相同。使用objdump -f查看文件的入口点——它将被称为“起始地址”。
该格式在此处中描述-您应该使用程序头而不是节头将ELF映像加载到内存中(我怀疑有30个程序头),并且入口点将由ELF头中的e_entry字段描述。

好的,知道了。原来这个格式的起始地址恰好是400130。无论如何,我知道我正在正确的位置开始了。运行程序时,除了文本和数据之外,我需要包含其他部分吗?也许是只读数据(rodata)?我不确定。 - Dan Snyder
如果您使用程序头(应该这样做,因为您关心ELF文件的“执行视图”,而不是“链接器视图”),则不会命名节。但是,是的,您还需要关注其他部分。查看objdump -h的输出-任何包含ALLOC或LOAD的部分可能需要加载到内存中。我不完全确定是否是这种情况,因为我使用程序头而不是节头来加载ELF映像。 - Aidan Cully
objdump -p 命令会告诉你程序头是用来干什么的。 - Aidan Cully
你需要使用.rodata,这很可能是常量静态对象的存储位置。你需要为.bss(未初始化数据)分配内存;它们不包含在文件中。还有一些其他的代码段,如.ctors.dtors.init.fini,也可能存在于文件中。 - Mike Seymour
头文件是用来干什么的?(我对ELF格式不是特别熟悉) - Dan Snyder
我建议阅读我提供的文档。引用:“如果存在程序头表,则告诉系统如何创建进程映像。用于构建进程映像(执行程序)的文件必须具有程序头表;可重定位文件不需要。节头表包含描述文件节的信息。每个节在表中都有一个条目;每个条目都提供诸如节名称、节大小等信息。在链接期间使用的文件必须具有节头表;其他目标文件可能有也可能没有。”它还描述了.bss、.data等内容。 - Aidan Cully

1
使用 ELF 头文件的 e_entry 字段来确定程序计数器的设置位置。

显然我将我的PC设置到了正确的位置。之前我只是先加载我的.text部分,通过引用转储文件中的第一个地址自动确定我的PC起始点。现在我可以更有把握地使用这个方法来获取正确的值。 - Dan Snyder

1

查看Elf32_Ehdr.e_entry(如果您在64位平台上,则为Elf64_Ehdr.e_entry)。 您至少还应包括.bss节,该节为空,但在磁盘ELF映像中具有“内存”大小。

维基百科将为您提供所有必要的文档

编辑:

这是来自我当前计算机上的objdump -h /usr/bin/vim的输出:

Sections:
Idx Name         Size      VMA               LMA               File off  Algn
...
22 .bss          00009628  00000000006df760  00000000006df760  001df760  2**5
                 ALLOC
23 .comment      00000bc8  0000000000000000  0000000000000000  001df760  2**0
                 CONTENTS, READONLY

请注意,File off 对于.bss.comment是相同的,这意味着磁盘文件中的.bss为空,但在内存中应为0x9628字节。

我的.bss节实际上并不为空。这可能意味着什么?此外,我正在使用C++映射来表示我的内存,因此任何未分配值的位置都将默认为“0”。 - Dan Snyder
你怎么知道它不是空的? - Nikolai Fetissov
当我运行“readelf -x 15 helloworld”时,该节在许多位置具有元素。与“.text”一样密集。 - Dan Snyder
哦,不用在意,它非常空。我可能引用了错误的部分。 - Dan Snyder
如果标记为“ALLOC”,则需要在内存中分配部分空间,如果标记为“LOAD”,则需要从文件中加载它。 - Nikolai Fetissov
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接