静态链接库在程序编译阶段就完成了链接工作,完成链接后,依赖的库就都打入了可执行文件中,所以文件大小一般会比较大。
而动态库链接库是在程序运行时才被链接的,所以磁盘上只要保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。Linux环境下的动态链接对象都是以.so为扩展名的共享对象(Shared Object).

生成共享动态链接库

main_1.c

#include "hello.h"

int main()
{
    print_x(1);
    sleep(10000);
    return 0;
}

hello.c

#include <stdio.h>

void print_x(int x)
{
    printf("call hello.so x=%d\n",x);
}

生成共享动态链接库 gcc -fPIC -shared -o hello.so hello.c
将main函数链接此共享库 gcc -o main_1 main_1.c ./hello.so

PIC:Position Independnet Code -fPIC表示生成位置无关的代码
有些系统需要无论加载到什么位置都可以正常工作的位置无关代码。链接器需要提供额外的技巧来支持位置无关代码,与程序中无法做到位置无关的部分隔离开来。

通过/proc 文件系统可以查看动态链接的程序在运行时会加载的额外的库有哪些
Linux环境下:程序的链接, 装载和库[动态链接]-小白菜博客
除了我们程序本身的main_1的段,还依赖了

  • hello.so这个是我们创建的动态链接库
  • libc.so.6这个是hello文件中所依赖的
  • ld-linux-x86-64.so.2这个是linux上的动态链接器。 使用动态链接库的时候,操作系统在运行程序之间,会先将控制权交给动态链接器,即/lib64/ld-linux-x86-64.so.2,它完成了动态链接的工作之后再把控制权交给应用程序。所以会在进程空间中看到这个

通过动态链接生成的main_1可执行文件中存储了这个信息,通过 readelf -s main_1查看 .interp section的内容
image.png

.interp
This section holds the pathname of a program interpreter. If the file has a loadable segment that includes the section, the section's attributes
will include the SHF_ALLOC bit. Otherwise, that bit will be off. This section is of type SHT_PROGBITS.

但是这样的依赖动态链接库,对最终运行时的动态链接库的位置有要求,将hello.so移动位置后就无法找到了。
image.png

可执行文件的运行时入口

真正可执行文件的运行时入口并不是main函数,而是glibc的运行时库,在执行main函数之前需要做一些初始化的工作。大部分Linux程序的入口地址应该都是 glibc 中的_start 函数
Linux环境下:程序的链接, 装载和库[动态链接]-小白菜博客
objdump -d ../PartIV/sta_vs_dyn/dyn_loop
Linux环境下:程序的链接, 装载和库[动态链接]-小白菜博客
这个对应glibc中的一段入口函数。

基本上到这里就理解了程序的编译,链接和装载的过程。文章只是跟随视频学习过程的一点记录,有些阅读linux内核的源码没有完全跟进去,感兴趣的可以看看原作者的分享视频

https://www.bilibili.com/video/BV1hv411s7ew/