如何让gcc只生成可以直接加载到内存并执行的机器代码?
我想生成一个可以加载到内存中的文件(例如使用 mmap
),然后跳转到该内存的开头来运行代码。
理想情况下,我希望选择使代码可重定位(这可能效率低下)或指定代码期望加载的显式地址(这很痛苦),但其中任何一个都可能单独工作得很好。
I would like to produce a file that I can load into memory (for example with mmap
) and then jump to the start of that memory to run the code.
Ideally, I'd like the option of either making the code relocatable (which might be inefficient) or specifying an explicit address that the code expects to be loaded at (which is a pain), but either one would probably work fine on its own.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您想了解实用程序
objcopy
,通常是与 GCC 一起提供。它是 binutils 工具包的一个组件,其中最明显的成员是链接器,ld
。该过程是编译源文件并像往常一样链接它们。这将为您提供 elf(或其他可重定位的依赖于平台的二进制文件)格式的完整可执行文件。然后,您可以使用 objcopy 将可执行文件转换为平面二进制映像。
这对于准备从 ROM 运行的代码最有用,您需要确保使用适合您的目标平台的 C 运行时库,并且可能需要自定义链接描述文件并提供您自己的 C 运行时启动代码。
如果您的目标是获取类似于 .so 文件的内容,将其加载到现有进程中,那么请注意,共享库加载器的一些工作是实际完成链接,以便 .so 中的符号引用主可执行文件(或其他 .so 文件)中的地址的文件在加载时得到解析。使用 objcopy 不会这样做,因此以这种方式加载的函数可能很难正确使用现有的 C 运行时库及其维护的对象(例如打开的文件)。
无论您的目标是什么,您都需要控制链接器,以便将二进制文件定位到已知地址。为此,您需要编写链接器脚本。脚本语言的文档位于binutils 手册中。您将主要对“.text*”部分感兴趣,如果您计划拥有任何初始化的全局变量,则可能对“.rodata*”部分感兴趣。实际上安排初始化是留给读者的练习。
总的来说,这只是冰山一角。我建议花一些时间进行交叉编译器构建,看看这些东西在实践中是如何使用的。 AVR 和 MSP430 社区使用 GCC,有积极的参与,并且有廉价(通常甚至是开源)的硬件来启动。
You want to know about the utility
objcopy
, which is usually available along with GCC. It is a component of the binutils package of tools, the most visible member of which is the linker,ld
.The process is that you compile your source file(s) and link them generally as usual. That gives you a finished executable in elf (or another relocatable platform-dependent binary) format. You then use objcopy to transform the executable to a flat binary image.
This is most useful for preparing code to be run from ROM, where you would want to make sure you are using a suitable C runtime library for your target platform, and likely need to customize the linker script file as well as provide your own C runtime startup code.
If your goal is to get something that is sort of like a .so file, to be loaded into an existing process, then be aware that some of the work of the shared library loader is to actually finish linking so that symbols in the .so file that refer to addresses in the main executable (or other .so files) get resolved at load time. Using objcopy won't do that, and so it might be difficult for functions loaded this way to properly use your existing C runtime library and objects it maintains such as open files.
Regardless of your goals, you are going to need to seize control of the linker in order to locate your binary at a known address. To do that, you will need to craft a linker script. Documentation for the script language is in the binutils manual. You will be primarily interested in the ".text*" sections, and possibly in the ".rodata*" sections if you plan to have any initialized global variables. Actually arranging for that initialization is left as an exercise for the reader.
Overall, this is just the tip of a very large iceberg. I'd suggest spending some time with a cross compiler build to see how these things are used in practice. The AVR and MSP430 communities use GCC, have active participation, and inexpensive (and often even open source) hardware to get started.
您可以执行此操作,但需要检查目标文件格式。特别是,objcopy 命令可以将可执行文件转换为“平面”二进制文件(取决于您的目标平台)。也许是这样的:
请参阅您平台上的
man objcopy
了解更多详细信息。You can do this but you will need to go through the object file format. In particular, the
objcopy
command can transform an executable file to a "flat" binary file (depending on your target platform). Perhaps something like this:See
man objcopy
on your platform for more details.