C语言编译 随笔
这种在程序运行之前确定符号地址的过程叫做静态链接(Static Linking);如果需要等到程序运行期间再确定符号地址,就叫做动态链接(Dynamic Linking)。
Linux 下的 .so 必须要嵌入到可执行程序、作为可执行程序的一部分运行,它们所包含的符号的地址就是在程序运行期间确定的,所以称为动态链接库(Dynamic Linking Library)。
强符号和弱符号
点击查看代码
void __attribute__((weak)) f()
{
printf("original f..\n");
}
编译时链接所做的工作
链接过程将多个目标文以及所需的库文件(.so等)链接成最终的可执行文件(executable file)。
命令大致如下:
$ ld -o test.out test.o inc/mymath.o ...libraries...
上面可以看到最终连接依赖了两个文件,mymath.o test.0还有其他一些依赖库
链接的详细过程如下:
合并段
在elf文件中字节对齐是以4字节对齐的,在可执行程序中是以页的方式对齐的(一个页的大小为4k),因此如果我们在链接时将各个.o文件各个段单独的加载到可执行文件中,将会非常浪费空间:

因此我们需要合并段,调整段偏移,把每个.o文件的.text段合并在一起.data段合并在一起,这样在生成的可执行文件中,各个段都只有一个,如下图,由于在链接时只需要加载代码段(.text段)和数据段(.data段和.bss段)。因此合并段之后,在系统给我们分配内存时,只需要分配两个页面大小就可以,分别存放代码和数据
调整段偏移

汇总所有符号
每个obj文件在编译时都会生成自己的符号表,我们要把这些符号都合并起来进行符号解析
完成符号的重定位
在进行合并段,调整段偏移时,输入文件的各个段在连接后的虚拟地址就已经确定了,这一步完成后,连接器开始计算各个符号的虚拟地址,因为各个符号在段内的相对位置是固定的,所以段内各个符号的地址也已经是确定的了,只不过连接器需要给每个符号加上一个偏移量,使他们能够调整到正确的虚拟地址,这就是符号的重定位过程
在 elf文件中,有一个叫重定位表的结构专门用来保存这些与从定位有关的信息,重定位表在elf文件中往往是一个或多个段

浙公网安备 33010602011771号