参考华清远见《嵌入式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
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 ""
3
# 1 ""
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时传入相关信息。