现在的位置: 首页 > 综合 > 正文

GCC之旅(1)— GCC的编译流程

2013年10月13日 ⁄ 综合 ⁄ 共 5586字 ⁄ 字号 评论关闭

 

参考华清远见《嵌入式linux应用程序开发详解》第三章

后缀名的说明:

.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:在这个阶段GCCtest.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 本身提供的功能,我们可以说gccld的关系是相当密切的),GG同样 也知道标准函数库的位置,并且在调用ld时传入相关信息。

 

【上篇】
【下篇】

抱歉!评论已关闭.