Executable and Linkable Format(.elf) 和 Object(.o) 文件的区别

Upg*_*ade 3 c elf object-files

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

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

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

Cod*_*odo 5

Let's make a simple example. You have three files:

cnt.h

void inc_counter();
void print_counter();
Run Code Online (Sandbox Code Playgroud)

cnt.c

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

static int counter= 0;

void inc_counter() {
    couner++;
}

void print_counter() {
    printf("Counter: %d\n", counter);
}
Run Code Online (Sandbox Code Playgroud)

main.c

#include <counter.h>

int main(char** args) {
    inc_counter();
    print_counter();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

You then compile cnt.c and main.c to create cnt.o and main.o.

  • cnt.o will contain the executable code for get_counter and inc_counter. For each one it has an entry point. But the code is not executable. The call of printf will not work as the address of printf is not yet know. So the file contains information that this will need to be fixed later.
  • main.o will contain the executable code for main and an entry point for it. Again, the references for inc_counter and print_counter will not work.

在第二步中,将链接文件和标准 C 库cnt.omain.o并创建一个可执行输出文件(带.elf或不带扩展名)。链接器将在调用inc_counter和函数之间创建缺失的链接inc_counter。它会对print_counterand做同样的事情printf,从而包括printf来自标准库的代码。

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

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


Pau*_*vie 1

  • 两个文件之间的实际区别是什么,或者如果我有多个源文件?

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

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

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

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

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

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

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