编译器生成的最终图像包含bin文件和扩展式加载程序格式ELF文件,这两者有什么区别,特别是ELF文件的功用。
Bin文件是纯二进制文件,没有内存修复或重定位,很可能有明确的指令要求在特定的内存地址加载。而...
ELF文件是可执行可链接格式,它由符号查找表和可重定位表组成,也就是说,它可以被内核加载到任何内存地址,并自动地将所使用的所有符号调整到该内存地址的偏移量上。通常,ELF文件有许多节,如“数据”、“文本”、“bss”等等......就是在这些节中,运行时可以计算在运行时动态调整符号的内存引用的位置。
Bin文件就是程序存储在ROM或者特定地址上的二进制数据,你可以直接加载这些数据,但是需要知道基地址,因为通常不包含在其中。
Elf文件包含了Bin信息,但是周围还有很多其他信息,如调试信息、符号等。它可以区分二进制中的代码和数据,并允许存在多个二进制数据块(将其转换成Bin文件时,会得到一个大的Bin文件,并使用填充数据来将其填充到下一个块)。它告诉你有多少二进制数据以及有多少要初始化为零的bss数据(gnu工具在创建正确的Bin文件方面存在问题)。
Elf文件格式是一种标准,ARM发布了其对标准的增强/变化。我建议每个人都编写一个Elf解析程序来了解其中的内容,不要使用库,只需使用规范中的信息和结构即可。这有助于解决GNU在创建.bin文件时出现问题以及调试链接脚本和其他问题,避免损坏您的Bin或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]
arm-none-eabi-objcopy
命令和参数--strip-all
是否与使用参数-O binary
的效果相同?我认为不是。第一个选项仍然会生成一个剥离了符号的ELF文件,而第二个选项会生成一个已经映射到适当位置的二进制文件。 - undefined"bin"是CPU执行前内存中的最终形式。
"ELF"是对其进行切割/压缩后的版本,因此CPU/MCU不能直接运行。
动态链接器首先必须充分地反转它(并将偏移量修改回到正确的位置)。但是MCU上没有链接器/操作系统,因此您必须将"bin"烧录进去。
此外,Ahmed Gamal 是正确的。编译和链接是两个单独的阶段;整个过程称为"构建",因此GNU编译器集合有单独的可执行文件:
一个用于编译器(技术上输出汇编代码),另一个用于汇编程序(输出ELF格式的目标代码),然后是用于链接器(将多个目标文件组合成单个ELF文件)的工具, 最后,在运行时,有动态链接器,它有效地将elf转换为bin,但纯粹在内存中,供CPU运行。
请注意,通常将整个过程称为"编译"(如GCC本身的名称),但在讨论具体细节时会导致混淆,就像在这种情况下一样,Ahmed正在澄清。 这是人类语言本身不精确的常见问题。
为避免混淆,GCC使用ELF格式输出目标代码(在内部使用汇编器),链接器只需获取其中几个(具有".o"扩展名), 并产生一个单一的组合结果,可能会将它们压缩(成"a.out")。但是所有这些文件,甚至".so"都是ELF。就像几个Word文档,每个以".chapter"结尾, 都被组合成最终的".book",所有这些文件都技术上使用相同的标准/格式,因此可以将".docx"作为扩展名。
"bin"有点像将书转换为".txt"文件,同时添加尽可能多的空格以等效于最终书籍的大小(打印在单个卷轴上),并有所有图片叠加的位置。
.o
也是ELF文件,类型为_relocatable_。还有另外两种类型:_executable_和_shared object_。所以,汇编器和链接器都会生成ELF文件。 - SenhorLucas
NOP
的文件而没有使用-f
(或-fbin
),它将编译为单个字节的0x90
,而不是带有-felf32
的400字节ELF容器。因此只有原始代码,没有容器元数据。NASM表示它主要用于MS-DOS .COM和.SYS文件。section
指令大多被忽略,只生成对齐。 - Ciro Santilli OurBigBook.com