侧边栏壁纸
  • 累计撰写 25 篇文章
  • 累计创建 11 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

位置无关代码

LinJHS
2024-03-19 / 0 评论 / 0 点赞 / 44 阅读 / 3041 字 / 正在检测是否收录...

位置无关代码

00 前言

在计算机领域中,地址无关代码(position-independent code,PIC),又称地址无关可执行文件(position-independent executable,PIE),是指可在主存储器中任意位置正确地运行,而不受其绝对地址影响的一种机器码。PIC广泛使用于共享库,使得同一个库中的代码能够被加载到不同进程的地址空间中。PIC还用于缺少内存管理单元的计算机系统中,使得操作系统能够在单一的地址空间中将不同的运行程序隔离开来。

通过这种方式,无限多个进程可以共享一个共享模块的代码段的单一副本,用户可以对 GCC 使用 -fpic 选项指示 GNU 编译系统生成 PIC 代码。

01 PIC 数据引用

编译器在数据段开始的地方创建了一个表,叫做全局偏移量表(Global Offset Table, GOT) 。在 GOT 中,每个被这个目标模块引用的全局数据目标(过程或全局变量)都有一个 8 字节条目。编译器还为 GOT 中每个条目生成一个重定位记录。在加载时,动态链接器会重定位 GOT 中的每个条目,使得它包含目标的正确的绝对地址。每个引用全局目标的目标模块都有自己的 GOT。

position-independent-code_pic1.png

02 PIC 函数调用

使用了“延迟绑定”解决这个问题,将过程地址的绑定推迟到了第一次调用该过程时

该技术的动机:

  • 对于共享库,应用程序通常只会使用其中很少的一部分,因此该方法可以避免不需要的重定位。

第一次调用,进行绑定的时候开销很大,但是其后的每次调用都只会花费一条指令和一个间接的内存引用。

使用了两个数据结构:

  • GOT 全局偏移量表——数据段的一部分
    • GOT 是一个数组,每个条目都是 8 字节
  • PLT 过程链接表(Procedure Linkage Table)——代码段的一部分
    • PLT 是一个数组,每个条目都是 16 字节
    • 每个被可执行程序调用的库函数都有他自己的 PLT 条目
    • PLT[0] 跳转到动态链接器中
    • PLT[1] 调用系统启动函数 __libc_start_main,初始化执行环境,调用 main 函数并处理其返回值
    • PLT[2] 开始,调用用户代码调用的函数

position-independent-code_pic2.png

上图展示了调用 addvec 的原理:

  1. 程序调用进入 PLT[2]
  2. 第一次跳转到下一条指令,将 addvec 的 ID 压入栈中,然后跳转到 PLT[0]
  3. 跳转到动态链接器中,使用两个栈条目确定 addvec 的运行时位置,重写 GOT[4],再跳回 addvec
  4. 后续再调用进入 PLT[2] 就可以直接跳转到 addvec 了

参考资料:

  1. 地址无关代码 https://baike.baidu.com/item/%E5%9C%B0%E5%9D%80%E6%97%A0%E5%85%B3%E4%BB%A3%E7%A0%81/22702477
  2. 《深入理解计算机系统》P489
0

评论区