【问题标题】:Difference between Executable and Linkable Format(.elf) and Object(.o) file可执行和可链接格式(.elf)和对象(.o)文件之间的区别
【发布时间】:2019-04-12 02:38:49
【问题描述】:

我正在查看关于 linux (man gcc) 的 gcc 手册中的 -c 选项 (gcc -c infile),其中指出:

-c:编译或汇编源文件,但不链接。链接阶段根本没有完成。最终输出是每个源文件的目标文件的形式。
默认情况下,源文件的目标文件名是通过将后缀 .c、.i、.s 等替换为 .o。

更重要的是,在检查 ELF 文件和目标文件(使用 file 命令)时,输出是相同的:

file ./out/main.o: ELF 32-bit LSB relocatable, Atmel AVR 8-bit, version 1 (SYSV), not stripped
file ./out/main.elf: ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, not stripped

所以它们都有相同的描述。 我的问题是:

  • 这两个文件之间的实际区别是什么,或者如果我有多个源文件?
  • 要运行的正确文件是什么,如何生成它?
  • 我需要目标文件,还是它们只是中间文件?
  • 如果我使用-c 选项和一些标志(-Wall -g -std=c99 -Os)编译一些源文件并从中获取目标文件,这些标志是否会在 ELF 文件生成时持续存在(如果我在生成 ELF 文件时可以跳过这些标志吗?在对象文件上使用它们)?

【问题讨论】:

  • 不一样的描述:一个是relocatable,另一个是executable
  • 哪个是可重定位的,哪个是可执行的
  • 它在file 输出中:ELF 32-bit LSB relocatable 用于.o 文件。
  • 哦,谢谢你的提示,我是盲人:)

标签: c elf object-files


【解决方案1】:
  • 这两个文件之间的实际区别是什么,或者如果我有多个源文件?

.o 文件包含来自一个源(编译单元)的已编译代码,但尚未准备好运行:它可以包含对来自库或其他目标文件的外部符号的引用。

  • 要运行的正确文件是什么,如何生成它?

也就是可执行文件(windows中的.exe)。它由链接阶段(由链接器)生成,该阶段搜索库和其他目标文件以解析 .o 文件中的外部引用。

  • 我需要目标文件,还是它们只是中间文件?

是的,您需要它们才能链接它们,但它们是中间文件。

  • 如果我用 -c 选项和一些标志( -Wall -g -std=c99 -Os )编译一些源文件并从中获取目标文件,这些标志是否会在 ELF 文件生成时保留(我可以跳过这些标志吗?如果我在对象文件上使用它们,则生成 ELF 文件时)?

某些标志在确定 .o 文件的意义上“持续存在”,但不是全部。 -Wall 仅在编译期间给出警告,-Os 指定某种优化类型,这将导致 .o 文件对执行的代码进行一些优化。

【讨论】:

  • Unix 不使用扩展名来指示可执行文件(它使用权限位)。 .a 是档案的扩展名。
  • 感谢您的快速回答,更重要的是,您能告诉我/指向某个地方,关于如何生成 .map 文件吗?我猜它们是链接阶段的一些辅助文件(使用链接器时,我对吗?)
  • 不,我不能,因为我不知道 gcc。但是你可以阅读文档。
  • @Upgrade -Xlinker -Map=output.map 用于链接步骤
  • 他们会列出符号
【解决方案2】:

让我们做一个简单的例子。你有三个文件:

cnt.h

void inc_counter();
void print_counter();

cnt.c

#include <stdio.h>
#include <cnt.h>

static int counter= 0;

void inc_counter() {
    couner++;
}

void print_counter() {
    printf("Counter: %d\n", counter);
}

ma​​in.c

#include <counter.h>

int main(char** args) {
    inc_counter();
    print_counter();
    return 0;
}

然后编译cnt.cmain.c 以创建cnt.omain.o

  • cnt.o 将包含get_counterinc_counter 的可执行代码。对于每一个,它都有一个入口点。但代码不可执行。 printf 的呼叫将无法工作,因为 printf 的地址尚不知道。因此,该文件包含稍后需要修复的信息。
  • main.o 将包含main 的可执行代码及其入口点。同样,inc_counterprint_counter 的引用将不起作用。

在第二步中,文件cnt.omain.o 和标准C 库将被链接并创建一个可执行的输出文件(带有.elf 或无扩展名)。链接器将在inc_counter 的调用和inc_counter 函数之间创建缺失的链接。它对print_counterprintf 执行相同的操作,从而包括标准库中printf 的代码。

因此,虽然这两种文件类型主要由可执行代码组成,但.o 文件仅包含代码片段,.elf 文件包含完整程序。

注意:创建或使用动态链接库时还有其他变化。但为了简单起见,我将它们排除在外。

【讨论】:

  • 正如我上面问的,你能帮我/给我一些生成 .map 文件的文档吗?更何况带有 *.out 扩展名的文件是什么?
猜你喜欢
  • 1970-01-01
  • 2019-04-08
  • 2014-08-30
  • 1970-01-01
  • 2016-05-28
  • 2023-03-20
  • 2013-05-16
  • 1970-01-01
  • 2014-01-16
相关资源
最近更新 更多