后缀名的说明:
.i 已经过预处理的C原始程序 .ii 已经过预处理的C++原始程序 .s/.S 汇编语言原始程序 .h 预处理文件(头文件) .o 目标文件 .a/.so 编译后的库文件 |
GCC编译流程分为4个步骤
1. 预处理(Preprocessing)
2. 编译(Compiling)
3. 汇编(Assembling)
4. 链接(Linking)
test.c
1 #include <stdio.h> 2 int main(void) 3 { 4 printf("Hello World!/n"); 5 return 0; 6 } |
1. 预处理(Preprocessing):在这个阶段GCC将头文件包含进test.c文件,并生成文件test.i。
执行下面命令生成test.i:
[root@localhost gccinfo]# gcc -E test.c -o test.i |
test.i的文件内容:
1 # 1 "test.c" 2 # 1 "<built-in>" 3 # 1 "<command-line>" 4 # 1 "test.c" 5 # 1 "/usr/include/stdio.h" 1 3 4 6 # 28 "/usr/include/stdio.h" 3 4 7 # 1 "/usr/include/features.h" 1 3 4 8 # 335 "/usr/include/features.h" 3 4 9 # 1 "/usr/include/sys/cdefs.h" 1 3 4 10 # 360 "/usr/include/sys/cdefs.h" 3 4 …………. 750 # 2 "test.c" 2 751 int main(void) 752 { 753 printf("Hello World!/n"); 754 return 0; 755 } |
2. 编译(Compiling):在这个阶段GCC检查test.i代码的规范性,确定有没有语法错误。确认无误后,则把test.i转化为汇编代码文件test.s。
执行下面命令生成test.s:
[root@localhost gccinfo]# gcc -S test.i -o test.s |
test.s的文件内容:
1 .file "test.c" 2 .section .rodata 3 .LC0: 4 .string "Hello World!" 5 .text 6 .globl main 7 .type main, @function 8 main: 9 leal 4(%esp), %ecx 10 andl $-16, %esp 11 pushl -4(%ecx) 12 pushl %ebp 13 movl %esp, %ebp 14 pushl %ecx 15 subl $4, %esp 16 movl $.LC0, (%esp) 17 call puts 18 movl $0, %eax 19 addl $4, %esp 20 popl %ecx 21 popl %ebp 22 leal -4(%ecx), %esp 23 ret 24 .size main, .-main 25 .ident "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)" 26 .section .note.GNU-stack,"",@progbits |
3. 汇编阶段(Assembling):在这个阶段GCC把test.s文件中的汇编代码转化为目标机器的机器代码文件test.o,为二进制文件。
执行下面命令生成test.o:
[root@localhost gccinfo]# gcc -c test.s -o test.o |
执行以下命令产看test.o
[root@localhost gccinfo]# od -t c test.o |
test.o文件内容:
0000000 177 E L F 001 001 001 /0 /0 /0 /0 /0 /0 /0 /0 /0 0000020 001 /0 003 /0 001 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0000040 354 /0 /0 /0 /0 /0 /0 /0 4 /0 /0 /0 /0 /0 ( /0 0000060 /v /0 /b /0 215 L $ 004 203 344 360 377 q 374 U 211 0000100 345 Q 203 354 004 307 004 $ /0 /0 /0 /0 350 374 377 377 0000120 377 270 /0 /0 /0 /0 203 304 004 Y ] 215 a 374 303 /0 0000140 H e l l o W o r l d ! /0 /0 G C 0000160 C : ( G N U ) 4 . 3 . 0 2 0000200 0 0 8 0 4 2 8 ( R e d H a t 0000220 4 . 3 . 0 - 8 ) /0 /0 . s y m t 0000240 a b /0 . s t r t a b /0 . s h s t 0000260 r t a b /0 . r e l . t e x t /0 . 0000300 d a t a /0 . b s s /0 . r o d a t 0000320 a /0 . c o m m e n t /0 . n o t e 0000340 . G N U - s t a c k /0 /0 /0 /0 /0 /0 0000360 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 * 0000420 /0 /0 /0 /0 037 /0 /0 /0 001 /0 /0 /0 006 /0 /0 /0 0000440 /0 /0 /0 /0 4 /0 /0 /0 + /0 /0 /0 /0 /0 /0 /0 0000460 /0 /0 /0 /0 004 /0 /0 /0 /0 /0 /0 /0 033 /0 /0 /0 0000500 /t /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 X 003 /0 /0 0000520 020 /0 /0 /0 /t /0 /0 /0 001 /0 /0 /0 004 /0 /0 /0 0000540 /b /0 /0 /0 % /0 /0 /0 001 /0 /0 /0 003 /0 /0 /0 0000560 /0 /0 /0 /0 ` /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0000600 /0 /0 /0 /0 004 /0 /0 /0 /0 /0 /0 /0 + /0 /0 /0 0000620 /b /0 /0 /0 003 /0 /0 /0 /0 /0 /0 /0 ` /0 /0 /0 0000640 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 004 /0 /0 /0 0000660 /0 /0 /0 /0 0 /0 /0 /0 001 /0 /0 /0 002 /0 /0 /0 0000700 /0 /0 /0 /0 ` /0 /0 /0 /r /0 /0 /0 /0 /0 /0 /0 0000720 /0 /0 /0 /0 001 /0 /0 /0 /0 /0 /0 /0 8 /0 /0 /0 0000740 001 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 m /0 /0 /0 0000760 - /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 001 /0 /0 /0 0001000 /0 /0 /0 /0 A /0 /0 /0 001 /0 /0 /0 /0 /0 /0 /0 0001020 /0 /0 /0 /0 232 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001040 /0 /0 /0 /0 001 /0 /0 /0 /0 /0 /0 /0 021 /0 /0 /0 0001060 003 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 232 /0 /0 /0 0001100 Q /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 001 /0 /0 /0 0001120 /0 /0 /0 /0 001 /0 /0 /0 002 /0 /0 /0 /0 /0 /0 /0 0001140 /0 /0 /0 /0 244 002 /0 /0 240 /0 /0 /0 /n /0 /0 /0 0001160 /b /0 /0 /0 004 /0 /0 /0 020 /0 /0 /0 /t /0 /0 /0 0001200 003 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 D 003 /0 /0 0001220 022 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 001 /0 /0 /0 0001240 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001260 /0 /0 /0 /0 001 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001300 004 /0 361 377 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001320 003 /0 001 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001340 003 /0 003 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001360 003 /0 004 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001400 003 /0 005 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001420 003 /0 /a /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001440 003 /0 006 /0 /b /0 /0 /0 /0 /0 /0 /0 + /0 /0 /0 0001460 022 /0 001 /0 /r /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 0001500 020 /0 /0 /0 /0 t e s t . c /0 m a i n 0001520 /0 p u t s /0 /0 /0 024 /0 /0 /0 001 005 /0 /0 0001540 031 /0 /0 /0 002 /t /0 /0 /n 0001551 |
4. 链接(Linking):在成功编译之后,就进入了链接阶段。在这里涉及到一个重要的概念:函数库。重新查看这个小程序时,在这个程序中并没有定义“printf”的函数实现,且在预编译中包含进的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,Gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。
函数库一般分为静态库和动态库两种。静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a” 。动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。GCC 在编译时默认使用动态库。完成了链接之后,GCC 就可以生成可执行文件。
执行以下命令生成可执行文件test
[root@localhost gccinfo]# gcc test.o -o test |
同时也可以通过od命令产看其内容。
以上4个编译步骤可以一次完成,执行下面命令即可:
[root@localhost gccinfo]# gcc test.c -o test |
编译程序时,gcc会自动帮你连接所有编译的文件名及标准函数库. 首先GCC会把所有的原始文件都转成目标文件,然后会自动调用linker 来连接相关文件名(事实上linker是个文件名为ld的程序,而不是gcc 本身提供的功能,我们可以说gcc和ld的关系是相当密切的),GG同样 也知道标准函数库的位置,并且在调用ld时传入相关信息。