如何让gcc只生成可直接加载到内存并执行的机器码?

18

我想生成一个文件,可以将其加载到内存中(例如使用 mmap),然后跳转到该内存的起始位置执行代码。

理想情况下,我希望有两种选择:使代码可重定位(可能效率低下)或指定代码期望加载的显式地址(比较麻烦),但单独使用其中任何一种都应该可以。


这不就是一个目标文件吗? - aaronasterling
1
不,至少来说,目标文件包含它们导出的符号信息(供链接器使用)。 - David X
2
你不想使用dll/共享库的具体原因是什么?使用裸二进制文件存在很多陷阱。 - snemarch
@snemarch,我知道这一点,如果我想编写一个库或插件系统,我会使用共享对象,但我现在不是在做那个。(mmap只是一个(糟糕的)例子,但我能想到的唯一好的例子涉及BIOS调用或设备控制寄存器的poke,我不想查找) - David X
2个回答

16

你可以通过目标文件格式来实现,特别是objcopy命令可以将可执行文件转换为“平面”二进制文件(取决于你的目标平台)。也许可以像这样做:

gcc -o test test.c
objcopy -O binary test test.bin

请在您的平台上查看 man objcopy 以获取更多详细信息。


+1,我知道有这样的功能。你知道我需要在特定地址加载吗? - David X
是的,你会看到。它将是链接器被告知要链接的地址。请注意,通常您不会看到链接器的控制文件,因此您可能不知道它在哪里... - RBerteig
我应该在哪里找到控制文件? - David X
尝试使用ld --verbose或者gcc -Wl,--verbose来确保你看到的是真正的名称。你需要在详细信息中搜索一下。我在我的回答中添加了一个链接,指向相关的ld手册部分。 - RBerteig

8
你想了解与GCC一起提供的实用程序objcopy。它是binutils工具包的组成部分,其中最明显的成员是链接器ld
流程是编译源文件并像通常一样进行链接。这将为您提供elf(或其他可重定位平台相关二进制)格式的完成可执行文件。然后,您可以使用objcopy将可执行文件转换为平面二进制图像。
这对于准备从ROM运行代码非常有用,您需要确保使用适合目标平台的C运行时库,并且很可能需要自定义链接器脚本文件以及提供自己的C运行时启动代码。
如果您的目标是获得类似于.so文件的东西,以便加载到现有进程中,请注意共享库加载器的一些工作实际上是完成链接,以便在加载时解析.so文件中引用主可执行文件(或其他.so文件)地址的符号。使用objcopy无法做到这一点,因此以这种方式加载的函数可能难以正确使用您现有的C运行时库和维护的对象,例如打开的文件。
无论您的目标如何,您都需要掌握链接器以便将您的二进制文件定位到已知地址。为此,您需要编写一个链接器脚本。脚本语言的文档在binutils手册中。您将主要关注“.text*”部分,并且如果计划有任何初始化的全局变量,则可能还会关注“.rodata*”部分。实际安排该初始化留给读者作为练习。
总的来说,这只是一个庞大冰山的一角。我建议花些时间使用交叉编译器构建来实际了解这些东西的使用方式。AVR和MSP430社区使用GCC,有积极参与,并提供廉价(甚至开源)的硬件以供入门。

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