c的编译过程整体分为4个步骤
1. 预编译
预编译的过程主要处理相关的c文件,主要处理c文件涉及的相关的预编译指令,比如#include, #define, 条件编译#if #ifdef等等。
在预编译阶段会进行宏展开,预编译完成后的文件不再包含任何的宏定义
预编译指令
# 针对hello.c预编译指令如下
gcc -E hello.c -o hello.i
2. 编译
编译过程就是一系列的词法分析、语法分析将预编译完成的文件转化为汇编文件
编译指令
# 针对hello.c编译指令如下, hello.c 预编译产生hello.i文件
gcc -S hello.i -o hello.s
查看一下简单的hello world 文件生成的汇编指令
cat hello.s
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 11, 0 sdk_version 11, 1
.globl _main ## -- Begin function main
.p2align 4, 0x90
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $32, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
leaq L_.str(%rip), %rdi
movb $0, %al
callq _printf
xorl %ecx, %ecx
movl %eax, -20(%rbp) ## 4-byte Spill
movl %ecx, %eax
addq $32, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "Hello World"
.subsections_via_symbols
3. 汇编
汇编器会将编译生成的汇编文件翻译成对应的机器指令
汇编指令
# 针对上文hello.s通过汇编指令生成hello.o
gcc -c hello.s -o hello.o
#hello.o 即是日常所说的目标文件
4. 链接
链接即是将上文生成的目标文件转化为可执行文件,链接过程比较复杂,涉及目标文件依赖分析替换,地址变更等
链接指令
ld # 链接器需要指定对应的头文件
gcc编译器常见语法:
-c:只进行编译,不进行链接,输出的是与源文件同名的.o文件。
-o:指定生成的文件的名称。链接生成可执行文件,这个参数后可以带可执行文件的名字,如果没有指定可执行文件的名字,则会默认为a.out。
-S:输出汇编代码文件,输出一个与源文件同名的.s文件,这个文件中的内容为汇编程序。
-O:在编译链接的过程中进行优化,在编译过程中对代码进行优化,代码经过优化后再利用汇编程序翻译成目标代码。