如何让gcc只生成可以直接加载到内存并执行的机器代码?
我想生成一个可以加载到内存中的文件(例如使用mmap
),然后跳转到该内存的开头来运行代码。
理想情况下,我希望选择使代码可重定位(可能效率低下)或指定代码期望加载的显式地址(这很痛苦),但任何一个都可能自行正常工作。
您可以这样做,但您需要完成目标文件格式。 特别是, objcopy
命令可以将可执行文件转换为“平面”二进制文件(取决于您的目标平台)。 也许是这样的:
gcc -o test test.c objcopy -O binary test test.bin
有关详细信息,请参阅您平台上的man objcopy
。
您想了解实用程序objcopy
,它通常与GCC一起提供。 它是binutils工具包的一个组件,其中最明显的成员是链接器ld
。
过程是您编译源文件并像往常一样链接它们。 这为您提供了elf(或其他可重定位平台的二进制)格式的可执行文件。 然后使用objcopy将可执行文件转换为平面二进制图像。
这对于准备从ROM运行的代码非常有用,您可以在其中确保为目标平台使用合适的C运行时库,并且可能需要自定义链接描述文件以及提供自己的C运行时启动代码。
如果你的目标是获得类似.so文件的东西,要加载到现有进程中,那么请注意共享库加载器的一些工作是实际完成链接以便.so中的符号引用主可执行文件(或其他.so文件)中的地址的文件在加载时得到解析。 使用objcopy不会这样做,因此以这种方式加载的函数可能很难正确使用现有的C运行时库和它维护的对象,例如打开的文件。
无论您的目标是什么,您都需要抓住链接器的控制权,以便将二进制文件定位在已知地址。 为此,您需要制作链接描述文件。 脚本语言的文档在binutils手册中 。 如果您计划拥有任何初始化的全局变量,您将主要对“.text *”部分感兴趣,并且可能在“.rodata *”部分。 实际上,安排初始化是留给读者的练习。
总的来说,这只是一个非常大的冰山的一角。 我建议花一些时间使用交叉编译器构建来查看这些东西在实践中是如何使用的。 AVR和MSP430社区使用GCC,积极参与,以及廉价(通常甚至是开源)硬件即可开始使用。