动态链接和加载(2)
动态链接与加载原理
若干要素
- 编译成位置无关代码
- 对外部函数的调用是查表的
- 在运行(加载)的时候填表
我们就发明了GOT(Global Offset Table)
也就是table
有个有趣的问题
1 |
|
编译器遇到函数调用,应该翻译成哪种指令?
- 如果是同一个动态链接库 call foo (因为如果是一个库的,链接的时候相对地址已经确定下来了)
- 如果是另外一个动态链接库 call TABLE(foo)
这就需要PLT (Procedure Linkage Table)
- 函数太多,每个都标记区分太难看
- 编译器总是生成一个直接的call
来自另一个动态链接库 call foo@plt
更多的细节
对于一个动态链接的二进制文件,execve后的第一条指令在哪里?
- what are the first a few steps executed after execve() of a ELF dynamic link binary? (Chatgpt)
第一条指令在/lib64/ld-linux-x86-64.so.2 _start函数
也就是说,刚刚执行玩execve后,我们的pc指针指向了ld.so中的代码。
- 首先会加载这个ELF文件,把相关的段加载进地址空间中。
- 内核会根据查看程序头表(program header)中的PT_INTERP的判断是否需要动态链接。如果需要,内核就会把动态链接器(通常来说是ld-linux.so)加载进进程的地址空间中。
- 设置栈的初始状态。
- 把控制交给动态链接器:内核把pc指针设置为动态链接器的入口地址。
- 动态链接器的初始化,解析符号,重定位等。
- 把控制权交给程序(通常来说是_start函数)
- How can I compile an ELF binary that use an alternative dynamic loader than the default ld.so?(能否替换这个加载器)
gcc -o hello hello.c -Wl, –dynamic-linker=/path/to/my_ld.so
readelf -l hello | grep “program interpreter” 查看可执行文件的动态链接器
示例代码
ld.S —— 将来链接成动态链接库
1 |
|
hello.c
1 |
|
Makefile
1 |
|
- 当我们输入make指令并执行 ./a.out 时,我们看到,我们并没有输出Hello,而是输出了This is a loader. 这也就说明了我们的动态链接器确实换掉了,由于hello.c是动态链接的,所以内核会加载我们自己的动态链接器并执行。
动态链接和加载(2)
http://example.com/2023/08/02/操作系统/jyy操作系统/动态链接和加载(2)/