编译器生成的最终图像包含bin文件和扩展加载器格式的ELf文件,两者有什么区别,尤其是ELF文件的实用性。
5 回答
Bin 文件是一个纯二进制文件,没有内存修复或重定位,很可能它有明确的指令要加载到特定的内存地址。然而....
ELF文件是可执行链接格式,它由符号查找和可重定位表组成,也就是说,它可以由内核加载到任何内存地址,并且自动将所有使用的符号调整到它所在的内存地址的偏移量被装入。通常 ELF 文件有许多部分,例如“数据”、“文本”、“bss”,仅举几例……在这些部分中,运行时可以计算在何处调整符号的内存引用在运行时动态。
bin 文件只是进入 rom 或运行程序的特定地址的位和字节。您可以获取这些数据并按原样直接加载,您需要知道基地址是什么,因为通常不存在。
elf 文件包含 bin 信息,但它周围有许多其他信息,可能的调试信息、符号,可以将代码与二进制文件中的数据区分开来。允许多于一大块二进制数据(当您将其中一个转储到 bin 时,您会得到一个带有填充数据的大 bin 文件以将其填充到下一个块)。告诉您有多少二进制文件以及有多少 bss 数据需要初始化为零(gnu 工具在正确创建 bin 文件时遇到问题)。
elf 文件格式是一种标准,arm 在标准上发布了它的增强/变体。我建议每个人都编写一个精灵解析程序来了解其中的内容,不要为库而烦恼,只需使用规范中的信息和结构就可以了。在创建 .bin 文件以及调试链接器脚本和其他可能有助于弄乱 bin 或 elf 输出的事情时,有助于克服 gnu 问题。
一些资源:
- ARM 架构的 ELF
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf - 来自 wiki http://en.wikipedia.org/wiki/Executable_and_Linkable_Format的 ELF
ELF 格式一般是编译的默认输出。如果你使用 GNU 工具链,你可以使用 objcopy 将其翻译成二进制格式,例如:
arm-elf-objcopy -O binary [elf-input-file] [binary-output-file]
或使用 fromELF 实用程序(内置于大多数 IDE,例如 ADS):
fromelf -bin -o [binary-output-file] [elf-input-file]
bin 是内存在 CPU 开始执行之前查看的最后一种方式。
ELF 是它的切割/压缩版本,因此 CPU/MCU 无法直接运行。
(动态)链接器首先必须充分反转它(从而将偏移量修改回正确的位置)。
但是 MCU 上没有链接器/操作系统,因此您必须改为刷新 bin。
此外,Ahmed Gamal 是正确的。
编译和链接是独立的阶段;整个过程称为“构建”,因此 GNU 编译器集合具有单独的可执行文件:
一个用于编译器(技术上输出汇编),另一个用于汇编器(以 ELF 格式输出目标代码),然后一个用于链接器(将多个目标文件组合成一个 ELF 文件),最后在运行时,有一个动态链接器,它有效地将一个精灵变成一个 bin,但纯粹在内存中,供 CPU 运行。
请注意,通常将整个过程称为“编译”(就像 GCC 的名称本身一样),但是在讨论细节时会引起混淆,例如在这种情况下,艾哈迈德正在澄清。
由于人类语言本身的不精确性,这是一个常见问题。
为避免混淆,GCC 使用 ELF 格式输出目标代码(在内部使用汇编程序之后)。链接器只需要其中几个(带有 .o 扩展名),并产生一个组合结果,甚至可能将它们压缩(到“a.out”中)。
但是所有这些,甚至“.so”都是ELF。它就像几个 Word 文档,每个都以“.chapter”结尾,都被组合成一个最终的“.book”,所有文件在技术上都使用相同的标准/格式,因此可以有“.docx”作为扩展名。
然后 bin 有点像将书转换为“.txt”文件,同时添加尽可能多的空白,以等于最终书的大小(打印在单个线轴上),所有图片的位置都是覆盖。
我只想在这里纠正一点。ELF 文件由链接器生成,而不是编译器。
编译器任务在从源代码文件生成目标文件 (*.o) 后结束。链接器将所有 .o 文件链接在一起并生成 ELF。