动态链接(1):与位置无关代码
1 动态链接过程
- Linux命令行下运行一个程序,操作系统给程序开启一个进程
- 动态链接器被映射到程序地址空间,OS将控制权交给动态链接器
- 动态链接器解析可执行文件中未确定符号、需要链接的动态库
- 加载对应的动态库、进行重定位等工作
- 动态链接器将控制权交给可执行程序,运行程序
2 动态库的运行地址
加载到内存中的地址是随机的,根据地址空间空闲情况分配
动态库被装载到内存任意地址都可以运行,怎么实现?
3 装载时重定位
3.1 基本思想
- 可执行文件中对所有绝对地址的引用,等动态库加载到内存, 地址确定后,再对可执行文件中的绝对地址引用进行重定位操作
- 实现:GCC编译使用–shared参数,生成共享动态链接库
3.2 产生的问题
对于每个进程,共享库都链接到一个不同的地址,导致动态库无法在多个进程之间共享,无法节省内存,违背了动态库的设计初衷
4 与地址无关的代码
4.1 特点
放到哪里,都可以执行,无须重定位,无须改变
4.2 实现思想
- 将指令中需要修改的部分分离出来,跟数据放在一起
- 剩余指令就可以做到与地址无关,被多个进程共享
- 数据和需要被修改的指令在每个进程都有一个副本,互不影响
4.3 如何实现
- 地址无关代码技术(PIC:position-independent code)
- 编译:gcc -fPIC -c main.c -o libsub.so
- 链接:gcc xxx.c -L. -lsub
5 PIC技术底层支撑
5.1 模块内部
ARM相对寻址
- PC作为基址,指令中的地址码段作为偏移量
- 两者相加得到的地址即为操作数的有效地址
- 对应的汇编指令:B/BL、ADR/ADRL
5.2 模块外部
核心问题:如何使引用外部模块的符号地址无关
核心思想:
- 动态链接重定位时,填写每个符号的 GOT(全局偏移表)
- 引用外部模块符号时查全局偏移表,间接跳转