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

时间:2010-09-01 06:00:05

标签: c gcc linker executable machine-code

我想生成一个可以加载到内存中的文件(例如mmap),然后跳转到该内存的开头运行代码。

理想情况下,我希望选择使代码可重定位(可能效率低下)或指定代码期望加载的显式地址(这很痛苦),但任何一个都可能正常工作独自一人。

2 个答案:

答案 0 :(得分:15)

您可以执行此操作,但您需要完成目标文件格式。特别是,objcopy命令可以将可执行文件转换为“平面”二进制文件(取决于您的目标平台)。也许是这样的:

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

有关详细信息,请参阅您平台上的man objcopy

答案 1 :(得分:6)

您想了解实用程序objcopy,它通常与GCC一起提供。它是binutils工具包的一个组件,其中最明显的成员是链接器ld

过程是您编译源文件并像往常一样链接它们。这为您提供了elf(或其他可重定位平台的二进制)格式的可执行文件。然后使用objcopy将可执行文件转换为平面二进制图像。

这对于准备从R​​OM运行的代码非常有用,您可以在其中确保为目标平台使用合适的C运行时库,并且可能需要自定义链接描述文件以及提供拥有C运行时启动代码。

如果你的目标是获得类似.so文件的东西,要加载到现有进程中,那么请注意共享库加载器的一些工作是实际完成链接,以便符号在引用主可执行文件(或其他.so文件)中的地址的.so文件在加载时解析。使用objcopy不会这样做,因此以这种方式加载的函数可能很难正确使用现有的C运行时库及其维护的对象,例如打开文件。

无论您的目标是什么,您都需要抓住链接器的控制权,以便将二进制文件定位在已知地址。为此,您需要制作链接描述文件。脚本语言的文档位于the binutils manual。您将主要对“.text *”部分感兴趣,如果您计划拥有任何已初始化的全局变量,则可能在“.rodata *”部分。实际上,安排初始化是留给读者的练习。

总的来说,这只是一个非常大的冰山一角。我建议花一些时间使用交叉编译器构建来查看这些东西在实践中是如何使用的。 AVR和MSP430社区使用GCC,积极参与,以及廉价(通常甚至是开源)硬件即可开始使用。