一些前置

怕自己忘记,写点前置知识

静态链接的函数地址在编译或者链接期间就确定了。动态链接的函数地址需要在运行时确定。

静态链接是把库直接链接到可执行文件,跟自己写的代码没什么区别。地址空间在用户空间。不同应用用同一份库,会各自复制一份。库函数的符号地址固定。不需要重新加载。

动态链接是放到系统空间,各应用共用一份,动态库的符号表需要重新计算,加载位置可能每次都不一样。

plt&got

1
2
3
4
5
6
7
8
9
#include <stdio.h>
void demo()
{
printf("Hello, World!\n");
}
int main()
{
demo();
}
1
$ gcc test.c -o test -m32

demo函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
000011cd <demo>:
11cd: f3 0f 1e fb endbr32
11d1: 55 push %ebp
11d2: 89 e5 mov %esp,%ebp
11d4: 53 push %ebx
11d5: 83 ec 04 sub $0x4,%esp
11d8: e8 3f 00 00 00 call 121c <__x86.get_pc_thunk.ax>
11dd: 05 fb 2d 00 00 add $0x2dfb,%eax
11e2: 83 ec 0c sub $0xc,%esp
11e5: 8d 90 30 e0 ff ff lea -0x1fd0(%eax),%edx
11eb: 52 push %edx
11ec: 89 c3 mov %eax,%ebx
11ee: e8 7d fe ff ff call 1070 <puts@plt>
11f3: 83 c4 10 add $0x10,%esp
11f6: 90 nop
11f7: 8b 5d fc mov -0x4(%ebp),%ebx
11fa: c9 leave
11fb: c3 ret

因为打印了以\n结尾的字符串,所以printf自动优化成了puts

demo函数调用的puts函数,因为put函数位于libc动态库内,所以必须在程序运行起来之后,才能知道puts函数的加载地址。

Q.当进程运行之后,glibc动态库装载之后,我们上面的call怎么修改地址呢?

  • 现代操作系统不允许修改代码段,只能修改数据段
  • 如果demo函数在一个动态库里,修改了代码段,就无法做到系统内所有进程共享同一个动态库。

所以puts函数只能在运行时写到数据段内。

链接阶段是将一个或者多个中间文件(.o文件)通过链接器将它们链接成一个可执行文件。

  • 各个中间文件(.o文件)之间的同名section合并
  • 对代码段,数据段以及各符号进行地址分配
  • 链接时重定位修正(调用puts函数的地址会在链接时进行修正,这个过程就被称为链接时重定位)

除了重定位过程,其它动作是无法修改中间文件中函数体内指令的,而重定位过程也只能是修改指令中的操作数,换句话说,链接过程无法修改编译过程生成的汇编指令

如果puts函数在普通的.o文件中定义,那么在链接阶段,它的地址就会被确定。但是如果在动态链接库中,则无法进行链接时重定位。

前面说过,程序运行时不能用重定位修改代码段,所以链接器会生成一段代码,通过这段代码获取动态库的链接地址,并完成调用。

1
2
3
4
5
6
7
8
9
10
11
.text
call puts_stub
...

puts_stub
mov rax, [puts函数的存储地址] // 获取puts函数重定位后的地址
jmp rax // 执行puts函数
.data
...
puts函数的存储地址:
这里存着puts函数重定位后的地址

动态链接需要用来存放外部函数的数据段,还有获取数据段地址的代码。

存放外部函数地址的段就是GOT(Global Offset Table),而那段获取地址的代码就是PLT。

img

之前有个疑问是,为什么需要plt,而不能直接返回到got。现在来看其实是got是数据段,没有执行权限,必须有plt代码段进行jmp执行。然后got表存储在数据段,不会影响程序执行的效率,有些不需要使用的函数不会被调用。

.got.plt 是GOT(Global Offset Table)的一部分,另一部分是 .got。
.got 存放全局变量引用地址。.got.plt 存放函数引用地址,也就是与PLT表一起起作用的辅助部分,对于外部函数的引用全部被分离出来放到了 .got.plt 中

最后

感谢海枫师傅的文章,虽然只看了一章,但是受益匪浅

https://www.zhihu.com/question/21249496/answer/126600437