ELF 文件和 bin 文件有啥区别?

Posted

技术标签:

【中文标题】ELF 文件和 bin 文件有啥区别?【英文标题】:What is the difference between ELF files and bin files?ELF 文件和 bin 文件有什么区别? 【发布时间】:2011-01-26 11:42:44 【问题描述】:

编译器生成的最终图像包含bin文件和扩展加载器格式的ELf文件,两者有什么区别,尤其是ELF文件的实用性。

【问题讨论】:

This is what NASM has to say。不是 ARM 特定的,但可能是相同的概念。例如,如果您编译一个仅包含 NOP 而不包含 -f(或 -fbin)的文件,它将编译为单个字节 0x90,而不是带有 -felf32 的 400 字节 ELF 容器。所以只有原始代码,没有容器元数据。 NASM 说它主要用于 MS-DOS .COM 和.SYS 文件。 section 指令大多被忽略,只生成对齐。 这是使用 bin 文件的一种方式:创建引导扇区以部署操作系统:***.com/a/32483545/895245 【参考方案1】:

Bin 文件是没有内存修复或重定位的纯二进制文件,它很可能有明确的指令要加载到特定的内存地址。而....

ELF 文件是可执行链接格式,由符号查找和可重定位表组成,也就是说,它可以由内核加载到任何内存地址,并且自动将所有使用的符号调整为偏移量它被加载到的那个内存地址。通常 ELF 文件有许多部分,例如“数据”、“文本”、“bss”,仅举几例……在这些部分中,运行时可以计算在何处调整符号的内存引用在运行时动态地。

【讨论】:

“很可能它有明确的指令要加载到特定的内存地址”:这是否意味着 bin 文件生成过程添加了用于将数据加载到特定地址的附加代码? 据我所知,bin文件就像从偏移量0运行程序并且数据段嵌入其中。如果这是错误的,请纠正我。 @MartinKersten 正确,bin 文件从偏移量 0 开始。 @t0mm13b 所以 .elf 文件可以像普通的 .hex 文件一样烧录到微控制器上,但是它需要更多的闪存,并且每次复位微控制器时,部分地址都会改变? @BlackyDucky,我不相信这是可能的。如果微控制器试图直接执行 ELF 数据,它会将标头和其他数据误解为指令,对吧?【参考方案2】:

一些资源:

    用于 ARM 架构的 ELFhttp://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf 来自维基的 ELFhttp://en.wikipedia.org/wiki/Executable_and_Linkable_Format

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 文件详细信息后添加的,并且 确实 附加了一种实用的技术。为此 +1。【参考方案3】:

bin 文件只是进入 rom 或运行程序的特定地址的位和字节。您可以获取这些数据并按原样直接加载,但您需要知道基地址是什么,因为通常不存在。

elf 文件包含 bin 信息,但它周围有许多其他信息,可能的调试信息、符号,可以区分代码和二进制文件中的数据。允许多于一大块二进制数据(当您将其中一个转储到 bin 时,您会得到一个带有填充数据的大 bin 文件,以将其填充到下一个块)。告诉您有多少二进制文件以及有多少 bss 数据需要初始化为零(gnu 工具无法正确创建 bin 文件)。

elf 文件格式是一种标准,arm 会在该标准上发布其增强/变体。我建议每个人都编写一个精灵解析程序来了解其中的内容,不要为库而烦恼,只需使用规范中的信息和结构就可以了。有助于克服 gnu 在创建 .bin 文件以及调试链接器脚本和其他可能会导致您的 bin 或 elf 输出混乱的事情时遇到的问题。

【讨论】:

0x7C00 听起来像是一个不需要使用精灵的引导加载程序。这是一个通用问题。操作系统将具有(虚拟)地址空间的规则,工具链需要以该操作系统规则为目标,然后文件格式将指示具有地址的可加载项以及加载后的入口点以及其他内容。 elf 只是一个容器,就像一个盒子,你必须为目标用例正确包装它。 如果你想将一些 ascii 打印到 vga,你可以编写一个 program 来执行包含一些数据或以数学方式即时生成数据或某种组合的操作,然后您将该程序加载到操作系统定义的代码空间中,然后运行它。您通常不会将数据直接推送到物理外围设备中,并且它是罕见的操作系统,无论如何都会让您这样做,或者允许它的加载器这样做。 对于裸机,尤其是如果此 elf 文件是引导加载程序和/或第一个程序运行,则入口点和 _start 不相关,因为您将 elf 文件用作工具的垫脚石对闪存进行编程(例如通过 jtag 的 openocd)或通过whatever-whatever-objcopy -O binary file.elf file.bin,然后以某种方式将该文件加载到闪存中。没有去尝试 x86 上的引导加载程序,但假设 bios 无法解析 elf 文件,因此它也需要是内存映像。所以一个-O二进制类型bin文件 单独的实体是硬件/逻辑或其他设计。对于操作系统,操作系统制定规则,对于微控制器,芯片/处理器设计制定规则。例如,如果有一个向量表,然后向量指向处理程序,则您必须将所有这些内容滚动到您的链接器脚本等中,以便可加载的数据注定要用于启动事物的闪存。 拓宽你的目标的规则,无论是操作系统、处理器还是多级引导加载程序等。你需要根据这些规则构建你的“二进制”,引导程序和链接脚本是最重要的。然后,每个目标以及如何应用该二进制文件以及支持哪些文件格式都非常广泛。假设 gnu 在许多主机开发平台上,elf 文件格式是默认输出,然后您根据需要使用工具(如果目标特定实用程序/加载程序)从 elf 提取或转换为其他内容。【参考方案4】:

我只想在这里纠正一点。 ELF 文件由链接器生成,而不是编译器。

编译器任务在从源代码文件生成目标文件 (*.o) 后结束。链接器将所有 .o 文件链接在一起并生成 ELF。

【讨论】:

投了反对票,因为它没有回答问题也不一定正确。从广义上讲,编译包括链接。引自ld documentation:通常编译程序的最后一步是运行ld。【参考方案5】:

bin 是内存在 CPU 开始执行之前查看的最后一种方式。

ELF 是它的切割/压缩版本,因此 CPU/MCU 无法直接运行。

(动态)链接器首先必须充分反转它(从而将偏移量修改回正确的位置)。 但是 MCU 上没有链接器/操作系统,因此您必须改为刷新 bin。

此外,Ahmed Gamal is correct. 编译和链接是独立的阶段;整个过程称为“构建”,因此 GNU 编译器集合具有单独的可执行文件:

一个用于编译器(技术上输出汇编),另一个用于汇编器(以 ELF 格式输出目标代码), 然后一个用于链接器(它将几个目标文件组合成一个 ELF 文件),最后,在运行时,有一个动态链接器, 这有效地将精灵变成了一个垃圾箱,但纯粹是在内存中,供 CPU 运行。

请注意,通常将整个过程称为“编译”(就像 GCC 的名称本身一样),但是在讨论细节时会引起混淆, 例如在这种情况下,艾哈迈德正在澄清。 由于人类语言本身的不精确性,这是一个常见问题。

为避免混淆,GCC 使用 ELF 格式输出目标代码(在内部使用汇编程序之后)。 链接器只需要其中几个(带有 .o 扩展名),并生成一个组合结果,甚至可能将它们压缩(到“a.out”中)。

但所有这些,甚至“.so”都是 ELF。 就像几个Word文档,每个都以“.chapter”结尾,都被组合成一个最终的“.book”, 其中所有文件在技术上都使用相同的标准/格式,因此可以使用“.docx”作为扩展名。

然后,bin 有点像将书转换为“.txt”文件,同时添加尽可能多的空白,以等于最终书的大小(打印在单个线轴上), 有所有图片要叠加的地方。

【讨论】:

(你拼错了mammary。)

以上是关于ELF 文件和 bin 文件有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

自己动手写一个操作系统——elf 和 bin 文件区别

自己动手写一个操作系统——elf 和 bin 文件区别

自己动手写一个操作系统——elf 和 bin 文件区别

可执行文件格式elf和bin

arm gcc 工具链作为 arm-elf 或 arm-none-eabi,有啥区别?

.got 和 .got.plt 部分有啥区别?