GCC之旅(1)--- GCC的编译流程
  ZklfkKGn8hpZ 2023年11月02日 73 0


 


博主:记得以前考过这么一题,说汇编是一个什么过程。。。。好吧,当时正处于远去了汇编语言,黯淡了编译原理的阶段,脑海中一阵晃动纠结~~~


不扎实呀呀~~~


参考华清远见《嵌入式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):在这个阶段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时传入相关信息。

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

上一篇: 什么是FrameBuffer? 下一篇: URL细节
  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

ZklfkKGn8hpZ