目录
一、单程序编译
(1)预处理
(2)编译为汇编语代码
(3)汇编
(4)链接
(5)运行
二、多程序编译
三、检错
四、库文件链接
五、gcc编译工具集中各软件
GCC
Binutils
C运行库
六、ELF文件
七、总结
八、参考文献
一、单程序编译
以下面这个程序为例
//hello.c #includeint main() { printf("hello worldn"); return 0; }
(1)预处理
终端输入
gcc -E hello.c -o hello.i
此时会得到一个名为hello.i的文件,这个文件就是预处理得到的文件,打开这个文件,发现只有最后几行是我们的程序,并且头文件不见了。实际上在我们程序的上面那几百行代码都是头文件stdio.h的内容,所以ggc -E的作用就是编译器在预处理后停止并输出预处理后的程序结果。
(2)编译为汇编语代码
终端输入
gcc -S hello.i -o hello.s
预处理后,将test.i文件编译后生成汇编代码
(3)汇编
对于hello.s,终端输入
gcc -c hello.s -o hello.o
即可将汇编代码文件编译为.o文件
(4)链接
终端输入
gcc hello.o -o hello
将之前生成的hello.o与c标准库进行链接,得到最终程序hello
(5)运行
终端输入
./hello
即可运行程序hello
二、多程序编译
假设我们现在的程序有两个源文件,对它们进行编译,可以使用
gcc test1.c test2.c -o test
上面这条代码可以将两个程序同时进行预处理,编译,链接,最后生成可执行程序test,上述命令可等效成以下命令
gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o
gcc test1.o test2.o -o test
三、检错
-pedantic 编译选项并不能保证被编译程序与 ANSI/ISO C 标准的完全兼容,它仅仅只能用来帮助 Linux 程序员离这个目标越来越近。或者换句话说,-pedantic 选项能够帮助程序员发现一些不符合 ANSI/ISO C 标准的代码,但不是全部,事实上只有 ANSI/ISO C 语言标准中要求进行编译器诊断的 那些情况,才有可能被 GCC 发现并提出警告
gcc -pedantic illcode.c -o illcod
除了-pedantic 之外,GCC 还有一些其它编译选项也能够产生有用的警告信息。这些选项大多以-W 开头,其中最有价值的当数-Wall 了,使用它能够使 GCC 产生尽可能多的警告信息
gcc -Wall illcode.c -o illco
GCC 给出的警告信息虽然从严格意义上说不能算作错误,但却很可能成为错误的栖身之所。一个优 秀的 Linux 程序员应该尽量避免产生警告信息,使自己的代码始终保持标准、健壮的特性。所以将 警告信息当成编码错误来对待,是一种值得赞扬的行为!所以,在编译程序时带上-Werror 选项,那 么 GCC 会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改,如下:
gcc -Werror test.c -o test
四、库文件链接
Linux下的大多数函数都默认将头文件放到/usr/include/目录下,而库文件则放到/usr/lib/目录下,当我们使用自己的办法查找所需头文件和库文件时,例如我们的程序 test.c 是在 linux 上使用 c 连接 mysql,这个时候我们需要去mysql官网下载MySQL Connectors 的C库,下载下来解压之后,有一个include文件夹,里面包含mysql connectors的头 文件,还有一个lib文件夹,里面包含二进制 so 文件libmysqlclient.so其中inclulde文件夹的路径是/usr/dev/mysql/include,lib文件夹是/usr/dev/mysql/lib
首先将test.c编译为目标文件
gcc –c –I /usr/dev/mysql/include test.c –o test.o
然后将所有目标文件链接成可执行文件
gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test
linux环境下库文件分为静态库(.a)和动态库(.so),二者的区别仅在于程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。
五、gcc编译工具集中各软件
GCC
GCC(GNU C Compiler)是编译工具。
Binutils
一组二进制程序处理工具,包括:addr2line、ar、objcopy、objdump、as、ld、 ldd、readelf、 size 等。
(1) addr2line:用来将程序地址转换成其所对应的程序源文件及所对应的代码行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对应的源代码位置。
(2) as:主要用于汇编。
(3) ld:主要用于链接。
(4) ar:主要用于创建静态库。
(5) ldd:可以用于查看一个可执行程序依赖的共享库。
(6) objcopy:将一种对象文件翻译成另一种格式,譬如将.bin 转换成.elf、或者将.elf 转换成.bin 等。
(7) objdump:主要的作用是反汇编。
(8) readelf:显示有关ELF文件的信息,请参见后文了解更多信息。
(9) size:列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小等。
C运行库
C 语言标准主要由两部分组成:一部分描述 C 的语法,另一部分描述 C 标准库。 C 标准库定义了一组标准头文件,每个头文件中包含一些相关的函数、变量、类 型声明和宏定义,譬如常见的 printf 函数便是一个 C 标准库函数,其原型定义 在 stdio 头文件中。 C 语言标准仅仅定义了 C 标准库函数原型,并没有提供实现。因此,C 语言编译 器通常需要一个 C 运行时库(C Run Time Libray,CRT)的支持。C 运行时库又 常简称为 C 运行库。
六、ELF文件
(1)ELF文件的段
ELF代表Executable and linkable Forma,是一种对可执行文件、目标文件和库使用的文件格式,跟Windows下的PE文件格式类似。ELF格式是是UNIX系统实验室作为ABI(Application Binary Interface)而开发和发布的,早已经是Linux下的标准格式了。
ELF 文件格式如下所示,位于ELF Header 和 Section Header Table之间的都是段(Section)。
一个典型的 ELF 文件包含下面几个段:
.text:已编译程序的指令代码段。
.rodata:ro 代表 read only,即只读数据(譬如常数 const)。
.data:已初始化的 C 程序全局变量和静态局部变量。
.bss:未初始化的 C 程序全局变量和静态局部变量。
.debug:调试符号表,调试器用此段的信息帮助调试
(2)反汇编 ELF
由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包 含的指令和数据,需要使用反汇编的方法。 使用 objdump -D 对其进行反汇编如下:
objdump -D hello
使用 objdump -S 将其反汇编并且将其 C 语言源代码混合显示出来:
gcc -o hello -g hello.c //要加上-g 选项 objdump -S hello
七、总结
了解了gcc工作的过程,学习了gcc检错的方法,还了解了ELF文件,同时也学会了ELF的反编译,但是由于对汇编语言的不熟悉,所以不是很能读懂
八、参考文献
https://blog.csdn.net/hnzwx888/article/details/89363761
https://blog.csdn.net/zhang2531/article/details/52085187?locationNum=6&fps=1
https://blog.csdn.net/weixin_48547489/article/details/109118682



