gcc编译过程

gcc简介

gcc的全称是GNU Compiler Collection,即GNU编译器套件.从名称可以看出来,gcc产出于GNU项目,它的初衷是为了给GNU操作系统专门写一款编译器,以解决不同GNU系统间编译器混乱的问题.现在,它已经可以编译众多语言,例如C, C++, Objective-C, Fortran, Ada, Go.并且成为了C, C++编译器的首选

gcc编译过程

废话少说,先上图:

gcc编译过程

如上,gcc的整个编译过程经历了预处理,编译,汇编,链接这几个过程

预处理

gcc会调用cpp程序进行预处理,将源代码文件中的文件包含语句(include),预编译语句(define等)进行分析和替换,并去掉注释

C源文件:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

#define A

int main()
{
printf("hello world!\n");
#ifdef A
printf("A is defined\n");
#endif
return 0;
}

执行gcc -E hello.c -o hello.i后的输出文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
# 864 "/usr/include/stdio.h" 3 4
extern int __uflow (FILE *);
extern int __overflow (FILE *, int);
# 879 "/usr/include/stdio.h" 3 4

# 2 "hello.c" 2




# 5 "hello.c"
int main()
{
printf("hello world!\n");

printf("A is defined\n");

return 0;
}

如上,include语句被替换为一段超长的代码,而define语句则被其语义所替代

编译

在预处理后,轮到编译器将源C代码编译成不可读的汇编代码.例如,执行gcc -S hello.i -o hello.s生成汇编文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
	.file	"hello.c"
.text
.section .rodata
.LC0:
.string "hello world!"
.LC1:
.string "A is defined"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rdi
call puts@PLT
leaq .LC1(%rip), %rdi
call puts@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 8.2.1 20180831"
.section .note.GNU-stack,"",@progbits

汇编文件似乎比预处理后的C文件小了很多???还是说由于只用到了printf函数,其他绝大多数代码都是没有用的信息-.-

汇编

接下来gcc调用汇编器as将汇编文件汇编为二进制文件.例如gcc -c hello.s -o hello.o

查看文件属性:

1
2
$ file hello.o 
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

链接

汇编后的二进制文件还不能执行,最后gcc会调用链接器ld链接二进制文件和其所需的库函数,使之成为真正的可执行文件.例如gcc -o hello hello.o

查看文件属性:

1
2
$ file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=dbda9b059dc7855d0d9a577ded54e3b2089ca5ff, not stripped

gcc参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-E:仅仅预处理,不编译,汇编,链接

-S:仅仅编译,不汇编,链接

-c:编译并汇编,但不链接

-o <file>:将输出写入文件

-I <dir>:指定头文件位置

-D macro[=defn]...:指定宏

-O level:指定优化等级.默认为0,可1-3递增

-Wall:输出警告信息

-g:为编译的程序添加调试信息,gdb调试时使用

-L <dir>:指定共享库所在位置,常与-l参数配合

-l <file>:指定共享库的名称

杂项

就C,C++的编译器来说,除了原本的GCC编译器,基于LLVM的CLANG编译器也较为流行

0%