博主:记得以前考过这么一题,说汇编是一个什么过程。。。。好吧,当时正处于远去了汇编语言,黯淡了编译原理的阶段,脑海中一阵晃动纠结~~~
不扎实呀呀~~~
参考华清远见《嵌入式linux应用程序开发详解》第三章
后缀名的说明:
|
GCC编译流程分为4个步骤
1. 预处理(Preprocessing)
2. 编译(Compiling)
3. 汇编(Assembling)
4. 链接(Linking)
test.c
|
1. 预处理(Preprocessing):在这个阶段GCC将头文件包含进test.c文件,并生成文件test.i。
执行下面命令生成test.i:
|
test.i的文件内容:
|
2. 编译(Compiling):在这个阶段GCC检查test.i代码的规范性,确定有没有语法错误。确认无误后,则把test.i转化为汇编代码文件test.s。
执行下面命令生成test.s:
[root@localhost gccinfo]# gcc -S test.i -o test.s |
test.s的文件内容:
|
3. 汇编阶段(Assembling):在这个阶段GCC把test.s文件中的汇编代码转化为目标机器的机器代码文件test.o,为二进制文件。
执行下面命令生成test.o:
|
执行以下命令产看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
|
同时也可以通过od命令产看其内容。
以上4个编译步骤可以一次完成,执行下面命令即可:
|
编译程序时,gcc会自动帮你连接所有编译的文件名及标准函数库. 首先GCC会把所有的原始文件都转成目标文件,然后会自动调用linker 来连接相关文件名(事实上linker是个文件名为ld的程序,而不是gcc 本身提供的功能,我们可以说gcc和ld的关系是相当密切的),GG同样 也知道标准函数库的位置,并且在调用ld时传入相关信息。