链接、装载与库

二、编译和链接

通常所说的编译分为四个步骤:预处理、编译、汇编和链接。

1、预处理过程主要处理那些以 # 开始的预编译命令如 #include/#define/#if 等,但保留 #pragma 编译器指令(因为编译器要使用它们),另外删除所有注释,添加行号和文件名标识。 

gcc -E test.c > test.i
cpp test.c > test.i

2、编译,生成 *.s 的汇编代码

gcc -S test.c
cc1 test.c

3、汇编,根据汇编指令和机器指令对照表翻译

gcc -c test.s -o test.o
as test.s -o test.o

4、链接,ld 命令要加上 crt 库和入口等东西,记不住的话,可以使用 gcc test.c -Wl,-v 来查看。

gcc test.o -o test
ld --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/../lib64/crt1.o /usr/lib/../lib64/crti.o /usr/local/gcc-4.8.2/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/crtbegin.o -L/usr/local/gcc-4.8.2/lib/gcc/x86_64-unknown-linux-gnu/4.8.2 -L/usr/local/gcc-4.8.2/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/local/gcc-4.8.2/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../..  -v -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/local/gcc-4.8.2/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/crtend.o /usr/lib/../lib64/crtn.o test.o

编译器的编译过程,一般分为6步:扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化。

链接从原理上讲,无非就是把一些指令对其它符号地址的引用加以修正,其过程包括了地址和空间分配,符号决议和重定位,简单的话,就是地址修正。

现在 PC 平台上流行的可执行文件格式,分为 Windows 下的 PE (Portable Executable) 和 Linux 下的 ELF (Executable Linkable Format),它们都是 COFF (Common file format) 格式的变种。

目标文件 (即 .o 文件) 与可执行文件的内容和结构很相似,所以与可执行文件采用同一种格式存储,除了目标文件之外,动态链接库和静态链接库(只是目标文件的打包,再加上一些索引)、核心转储文件也是按照可执行文件格式来存储的。

目标文件的内容包含了及其指令代码、数据,还有链接的时候需要的如符号表、调试信息、字符串等。目标文件格式将这些信息按不同的属性,以“节(Section)”的形式存储,有时候也叫“段(Segment)”,他们都表示一个一定长度的区域。

Linux 下可以使用 file 命令来查看相应的文件格式。

一般编译后的机器代码保存在 .text 段,已初始化的全局变量和局部静态变量保存在 .data 段,未初始化的全局变量和局部静态变量保存在 .bss 段。.data 段会为变量分配空间,而未初始化的全局变量和局部静态变量默认值都为0,为其分配空间没有必要。

将程序指令和程序数据分离开来,.bss 段是只读的,而且当多个副本同时运行时还可以实现共享指令(比如动态链接库)。

.bss 段只是为未初始化的全局变量和局部静态变量预留位置,并没有内容,所以也不占据空间。

原文地址:https://www.cnblogs.com/tianyajuanke/p/3696225.html