【链接、装载与库】动态链接中的延迟绑定(PLT)

系列文章

【链接、装载与库】程序的编译过程
【链接、装载与库】动态链接相关结构
【链接、装载与库】动态链接初体验

前言

动态链接是在运行时将各个模块的代码进行整合,静态链接是在编译时对各个模块的代码进行整合。
而运行时整合使得动态链接相对消耗了一些性能,为了减小这点带来的影响,动态链接中引入了延迟绑定(PLT),其基本思想是当函数第一次被用到时才进行绑定(符号查找、重定位等),如果没有用到则不进行绑定,接下来通过一个示例对延迟绑定进行分析。

正文

首先创建5个文件liba.c、liba.h、libb.c、libb.h、main.c。
内容分别为:
liba.c

int funca(int i)
{
	return i + 1;
}

liba.h

#ifndef LIBA_H
#define LIBA_H

int funca(int i);

#endif

libb.c

int funcb(int i)
{
	return i + 2;
}

libb.h

#ifndef LIBB_H
#define LIBB_H

int funcb(int i);

#endif

main.c

#include <stdio.h>
#include "liba.h"
#include "libb.h"

int main()
{
	int a;
	int b;
	a = funca(1);
	b = funcb(1);

	printf("a is %d,  b is %d\n", a, b);
}

输入如下指令分别生成liba.so、libb.so两个动态共享对象:
gcc -fPIC -shared -o liba.so liba.c
gcc -fPIC -shared -o libb.so libb.c
然后输入如下指令对main.c进行编译输出可执行文件main:
gcc -o main main.c ./liba.so ./libb.so
此时文件夹中的内容如下:
在这里插入图片描述
运行可执行文件main得到如下结果:
在这里插入图片描述
接下来对可执行文件main进行分析。
输入如下指令得到main的反汇编代码:
objdump -S main
其中main函数部分内容如下:
在这里插入图片描述
可以看到
调用funca函数部分代码为callq 660 <funca@plt>
调用funcb函数部分代码为callq 680 <funcb@plt>
调用printf函数部分代码为callq 670 <printf@plt>
找到反汇编代码中0x6600x6700x680部分的代码,内容如下:
在这里插入图片描述
以funcb为例,可以看到调转到0x680地址后执行的代码为去0x200fd0地址取出一个数值,将其赋值给PC指针继续执行。
要想查看0x200fd0地址处的内容,输入如下指令,得到main的二进制形式:
objdump -s main
找到我们想要的内容如下:
在这里插入图片描述
这部分叫做全局偏移表(GOT)
可以看到0x200fd0地址处的内容为86060000 00000000进行大小端转换之后就是0x686,而0x686处的代码则是:
在这里插入图片描述
也就是压栈一个数值2,然后执行0x650处的代码,0x650处代码如下:
在这里插入图片描述
可以看到这部分执行的代码为压栈GOT表第二项数据,跳转到GOT表第三项存储的函数地址开始执行。
GOT表的内容如下:

序号地址含义
第一项0x200fa8.dynamic段地址
第二项0x200fb0Module ID (模块编号)
第三项0x200fb8_dl_runtime_resolve()
第四项0x200fc0funca函数
第五项0x200fc8printf函数
第六项0x200fd0funcb函数

调用_dl_runtime_resolve函数用于把funcb的真实地址填写到GOT中,整个过程如下:
在这里插入图片描述
这是第一次调用funcb函数的时候,之后再调用funcb函数时,由于GOT表已经写入了funcb函数的真实地址,所以执行过程如下:
在这里插入图片描述
这样就实现了第一次调用funcb函数时完成了动态链接,之后就可以直接调用的效果。

在调用_dl_runtime_resolve时要压入funcb函数的符号下标。
所谓的符号下标是.rela.plt段中的下标,输入如下指令:
readelf -a main
找到.rela.plt段的内容如下:
在这里插入图片描述
第一列表示函数在GOT表中的地址,最后一列表示函数的符号名。
_dl_runtime_resolve获取符号下标之后,就可以通过符号名去别的模块查找函数地址,找到之后将函数地址填写到第一列存储的GOT表地址中,也就完成了动态链接。

  • 27
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值