可执行和可链接格式(.elf)与对象(.o)文件之间的区别

问题描述 投票:0回答:2

我在 Linux 上的 gcc 手册 (

man 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 文件时跳过这些标志吗?在目标文件上)?
c elf object-files
2个回答
11
投票

我们举一个简单的例子。您有这三个文件:

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);
}

main.c

#include <cnt.h>

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

然后编译

cnt.c
main.c
以创建
cnt.o
main.o

  • cnt.o
    将包含
    get_counter
    inc_counter
    的可执行代码。对于每一个它都有一个入口点。但该代码不可执行。
    printf
    的调用将不起作用,因为
    printf
    的地址尚不清楚。因此该文件包含稍后需要修复的信息。
  • main.o
    将包含
    main
    的可执行代码及其入口点。同样,
    inc_counter
    print_counter
    的引用将不起作用。

在第二步中,文件

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

因此,虽然这两种文件类型主要由可执行代码组成,但

.o
文件仅包含代码片段,而
.elf
文件包含完整的程序。

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


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

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

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

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

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

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

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

某些标志“持续存在”,因为它们决定了 .o 文件,但不是全部。

-Wall
仅在编译期间给出警告,
-Os
指定某种类型的优化,这将产生一个对所执行的代码进行一些优化的.o文件。

© www.soinside.com 2019 - 2024. All rights reserved.