地址无关代码和非地址无关代码主要区别在于代码中的地址引用方式

非地址无关代码

非地址无关代码所有的地址引用都是固定的绝对地址。编译器在编译时就确定了函数调用、全局变量访问等指令中的具体内存地址。

  • 编译和链接:在链接阶段,链接器会为函数调用和全局变量访问生成绝对地址(这里的绝对不是指物理内存地址,而是指它不依赖于相对偏移量,是一个固定的虚拟地址)。编译器和链接器会直接把目标函数的地址或变量的地址硬编码到指令中。
  • 运行时:当操作系统加载程序时,如果程序被加载到链接器预设的地址(或通过地址重定位调整到预设地址),那么一切正常。但如果该地址已被占用,程序就无法加载或需要复杂的地址重定位过程,这会影响加载速度。

地址无关代码

地址无关代码所有的地址引用都是相对地址。它不依赖于加载到内存中的具体位置,可以被加载到任何内存地址而无需修改。

  • 编译和链接:编译器使用全局偏移表( GOT)过程链接表( PLT)来间接访问函数和变量。

    • GOT:包含所有外部函数和全局变量的实际地址。代码访问变量时,首先会找到 GOT 中对应的条目,然后从那里读取实际地址。
    • PLT:用于处理外部函数调用。当调用一个外部函数时,代码会跳转到 PLT 的一个条目,PLT 再跳转到 GOT 中的地址,最终跳转到实际的函数。
  • 运行时:当程序加载时,操作系统只需要更新 GOT 和 PLT 中的地址即可,而不需要修改代码段中的任何指令。这使得整个代码段可以被多个进程共享,从而节省了大量内存。

PLT 和 GOT 的机制允许动态链接器在函数首次被调用时才去解析它的实际地址,这进一步加快了程序的启动速度。(延迟绑定 )