我在 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 文件时跳过这些标志吗?在目标文件上)? 我们举一个简单的例子。您有这三个文件:
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
文件包含完整的程序。
注意:当您创建或使用动态链接库时,还有其他变化。但为了简单起见,我将它们排除在外。
.o 文件包含来自一个源(编译单元)的已编译代码,但尚未准备好运行:它可以包含对库或其他目标文件中的外部符号的引用。
这是可执行文件(Windows 中为 .exe)。它由链接阶段(由链接器)生成,该阶段搜索库和其他目标文件以解析 .o 文件中的外部引用。
是的,您需要它们才能链接它们,但它们是中间文件。
某些标志“持续存在”,因为它们决定了 .o 文件,但不是全部。
-Wall
仅在编译期间给出警告,-Os
指定某种类型的优化,这将产生一个对所执行的代码进行一些优化的.o文件。