
学习链接为了:
gcc -Og -o prog main.c sun.c
-Og 生成的汇编的代码尽可能与源代码一致性,实际中一般用-O1,-O2
cpp -o main.i main.c
gcc -E -o main.i main.c
//cpp = c comiler(C 编译器)
//-E只进行预处理,不执行编译链接部分
cc -S -o main.s main.i
gcc -S -o main.s main.i
//cc = c compiler
//-S只进行编译操作
as -o main.o main.s
//as: assembler(汇编器)
ld -static -o prog main.o sum.o
//ld 链接器
在实际中链接这个过程,可能发生在多个过程当中。
在shell中调用操作系统中一个叫做加载器loader
的函数,它将可执行文件prog中的代码和数据复制到内存当中,然后将控制转移到这个程序的开头。
gcc -c main.c
readelf -h main.o
//读取ELF Header
目标文件中存放了代码和数据,具体总结下里面的内容。
符号表是ELF头文件其中的一个节。
通过objdump
和readelf
查看二进制文件。
利用符号表中的信息,进行链接的有关操作。
.bss
和COMMON
中分配的符号区别
为了构造可执行文件,链接器必须完成两个主要任务:
如果把所有标准C函数放在一个目标文件中,那么每个程序都需要一个标准函数的副本,这是一种内存浪费。
如果为每个函数都单独创建一个独立的可重定位的文件,把他们存放在一个文件中,对每一个单独文件的链接又会耗费大量时间,也有可能出错。
因此引出了静态库这一个概念,把相关函数封装成一个静态库。链接库会从其中复制使用到的相关模块到可执行文件当中。这样减少了不必要的模块的内存占用。
注意链接静态库的顺序,静态库文件一般放在最后。
为了解决了静态库的更新问题以及重复代码复制到每个进程中占据过大的内存问题,有了动态链接库。
区别静态库链接,在链接阶段只进行了重定向、提取了符号表信息,等到加载到内存执行时,通过动态链接器从动态链接库中重定位文本和数据到内存当中。
这样实现了不同正在运行的进程共享动态链接库。