20-动态链接和加载
20-动态链接和加载
libc.o静态链接
容易浪费空间
libc.so动态链接
生成位置无关代码,使用中间的table存放函数地址
借助编译器完成
用多个线程链接库,验证只有一个副本
是链接的同一份
地址空间是怎么分配的(虚拟内存)
动态链接(查表)

编译时,函数调用 = 查表(把函数调用替换成查表)
编译时,动态链接库调用 = 查表
1 | call *TABLE[printf@symtab] |
链接时,收集所有符号,“生成” 符号信息和相关代码:
1 |
|

1 | LOAD("libc.dl") |
gdb过程dlbox main.s
加载符号表,递归调用dlopen,调用libc.dl,导出符号,
putchar,exit填到全局的符号表,
解析第二个符号,libhello.dl
….
动态解析hello,hello不在main.dl里,是?
调用dlsym检查符号表,找到hello把地址填入符号表
执行DSYM(exit)
1 |
找到空位把符号填入符号表
前面的存放地址和函数名的表项,就是 GOT (Global Offset Table)
因为call 的偏移量是64位,跳不到远处
所以使用plt,作为中转,先跳到plt中,plt中存放GOT对应函数的地址
再次跳转到对应函数

数据的链接,plt怎么解决数据链接的问题
get_x会查表
get_y直接得到地址(hidden)
编译器默认extern变量来自另外一个共享库单元(保守)
gpt对objdump反汇编的分析
总结
- 变量
x:- 默认可见性(
visibility("default"))。 - 使用
mov指令,通过符号表获取地址。 - 可被其他模块或共享库访问。
- 默认可见性(
- 变量
y:- 隐藏可见性(
visibility("hidden"))。 - 使用
lea指令,直接计算地址,无需符号表查找。 - 仅在当前模块内部可见,无法被外部访问。
- 隐藏可见性(
- 性能影响:
- 隐藏符号(
y)链接效率更高,因为不需要符号表查找。 - 默认可见性符号(
x)灵活性更强,但动态链接时可能会引入额外开销。
- 隐藏符号(