GCC 一步到位
GCC 一步到位
GCC 简介
GCC 的意思也只是 GNU C Compiler 而已。经过了这么多年的发展,GCC 已经不仅仅能支持 C语言;它现在还支持 Ada 语言、C++ 语言、Java 语言、Objective C 语言、Pascal 语言、COBOL语言,以及支持函数式编程和逻辑编程的 Mercury 语言,等等。而 GCC 也不再单只是 GNU C 语言编译器的意思了,而是变成了 GNU Compiler Collection 也即是 GNU 编译器家族的意思了。另一方面,说到 GCC 对于操作系统平台及硬件平台支持,概括起来就是一句话:无所不在。
Binutils 工具包
一组二进制程序处理工具,包括:addr2line、ar、objcopy、objdump、as 、ld、ldd 、readelf 、size等。这一组工具是开发和调试不可缺少的工具
addr2line
来将程序地址转换成其所对应的程序源文件及所对应的代码行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对应的源代码位置
as
主要用于汇编
ld
主要用于连接
ar
主要用于创建静态库
静态库与动态库
将多个 .o 目标文件生成一个库文件,存在两种类型的库:静态库,动态库
Windows 中,静态库是后缀为 .lib 的文件,共享库是后缀为 .dll 的文件;在 Linux 系统中,静态库后缀为 .a ,动态库后缀为 .so
静态库与动态库对比
代码载入时刻不同
静态库:编译过程中已经被载入可执行程序,体积较大
动态库:可执行程序运行时载入内存,编译过程仅简单引用,代码体积较小
Linux 系统中可以使用 ldd 命令查看可执行程序依赖的共享库
多个程序需要共享库,采用动态库更节省内存
ldd
可以用于查看一个可执行程序的依赖的共享库
objcopy
将一种对象文件翻译成另一种格式,比如将 .bin 转换为 .elf 等
objdump
主要作用是反汇编
readelf
显示有关 ELF 文件的信息
size
列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小等
C 运行库
C 语言标准主要由两部分组成:一部分描述 C 的语法,另一部分描述 C 标准库。C 标准库定义了一组标准头文件,每个头文件中包含一些相关的函数、变量、型声明和宏定义,譬如常见的 printf 函数便是一个 C 标准库函数,其原型定义在 stdio 头文件中。
C 语言的标准仅仅定义了 C 标准库函数原型,并没有提供实现。因此,C 语言编译器通常需要一个 C 运行时库( C Run Time Libray , CRT )的支持。C 运行时库又常简称为 C 运行库。与 C 语言类似,c++ 也定义了自己的标准,同时提供相关支持库,成为 C++ 时运行库
GCC 编译过程
实际上,上述的编译步骤分为四个阶段:
1.预处理(也叫预编译,Preprocessing)
2.编译(Compilation)
3.汇编(Assenbly)
4.连接(Linking)
具体编译过程,查看我的另一篇博客:GCC 编译全过程
链接器链接后生成的最终文件为 ELF 格式可执行文件,一个 ELF 可执行文件通常被链接为不同的段,常见的段譬如:.text、.data、.rodata、.bss等
ELF 文件解析
ELF文件格式如图:
位于 ELF Header 和 Section Header Table 之间的都是段(Section)。一个典型的 ELF 文件包含下面几个段:
.text:以编译程序的指令代码段
.rodata:ro 代表 read only ,即只读数据(譬如常数 const 等)
.data:已初始化的 C 程序全局变量和静态局部变量
.bss:未初始化的 C 程序全局变量和静态局部变量
.debug:调试符号表,调试器用此段的信息帮助调试
可以使用以下命令查看各个 Section 的信息:
readelf -S hello
显示内容如下:
反汇编 ELF
由于 ELF 文件无法像普通文本一样打开,如果要直接查看一个 ELF 文件包含的指令和数据,需要进行反汇编
使用 objdump -D 反汇编,代码如下:
objdump -D main
显示内容如下:
或者使用 objdump -S 将其反汇编并将其 C 语言代码混合显示,代码如下:
gcc -o main -g main.c
objdump -S main
显示内容如下: