20-动态链接和加载

20-动态链接和加载

libc.o静态链接

容易浪费空间

libc.so动态链接

生成位置无关代码,使用中间的table存放函数地址

借助编译器完成

用多个线程链接库,验证只有一个副本

是链接的同一份

地址空间是怎么分配的(虚拟内存)

动态链接(查表)

image-20241207160836673

编译时,函数调用 = 查表(把函数调用替换成查表)

编译时,动态链接库调用 = 查表

1
call  *TABLE[printf@symtab] 

链接时,收集所有符号,“生成” 符号信息和相关代码

1
2
3
4
5
6
7
8
9
#define foo@symtab     1
#define printf@symtab 2
...
void *TABLE[N_SYMBOLS];
void load(struct loader *ld) {
TABLE[foo@symtab] = ld->resolve("foo");
TABLE[foo@printf] = ld->resolve("printf");
...
}

image-20241208152058135

1
2
3
4
5
LOAD("libc.dl")
LOAD("libhello.dl")
IMPORT(hello)
IMPORT(exit)
EXPORT(_start)

gdb过程dlbox main.s

加载符号表,递归调用dlopen,调用libc.dl,导出符号,

putchar,exit填到全局的符号表,

解析第二个符号,libhello.dl

….

动态解析hello,hello不在main.dl里,是?

调用dlsym检查符号表,找到hello把地址填入符号表

执行DSYM(exit)

1
#define DSYM(sym)   *sym(%rip)

找到空位把符号填入符号表

前面的存放地址和函数名的表项,就是 GOT (Global Offset Table)

因为call 的偏移量是64位,跳不到远处

所以使用plt,作为中转,先跳到plt中,plt中存放GOT对应函数的地址

再次跳转到对应函数

image-20241208121223400

数据的链接,plt怎么解决数据链接的问题

image-20241208171116351

get_x会查表

get_y直接得到地址(hidden)

编译器默认extern变量来自另外一个共享库单元(保守)

image-20241208181848498

gpt对objdump反汇编的分析

总结

  1. 变量 x
    • 默认可见性(visibility("default"))。
    • 使用 mov 指令,通过符号表获取地址。
    • 可被其他模块或共享库访问。
  2. 变量 y
    • 隐藏可见性(visibility("hidden"))。
    • 使用 lea 指令,直接计算地址,无需符号表查找。
    • 仅在当前模块内部可见,无法被外部访问。
  3. 性能影响
    • 隐藏符号(y)链接效率更高,因为不需要符号表查找。
    • 默认可见性符号(x)灵活性更强,但动态链接时可能会引入额外开销。