要解释重定位,首先需要理解程序是怎么链接的。程序链接的时候可以通过链接脚本将程序链接到指定地址上,可以链接成地址相关码也可以链接成地址无关码。
顾名思义,地址相关码就是把程序链接到指定地址上,在嵌入式开发中经常用到地址相关码的编译。由于嵌入式的板子资源有限,需要规划内存的使用,就需要合理规划bios、操作系统、嵌入式软件的地址。地址无关码就是程序可以被加载到任意地址上,但是程序的指令编译之后就是固定的,在函数调用、全局变量的使用的时候如何正确定位到指定地址上呢?
举一个例子,如果我们链接的地址是0x00000000,被调用的函数被链接到0x00010000上,如果指令的逻辑直接跳转到0x00010000,那就是地址相关码。如果要把程序加载到0x00200000上,那被调用的函数就被加载到0x002100000上,要想让指令正确运行,就需要做重定位。
常用的重定位技术是,将所有的全局符号放在全局偏移表中,在elf文件中就是.got段,如果涉及动态库的话就是.got.plt段。全局偏移表中放着全局符号的地址,由于链接的过程中知道全局偏移表的位置,只需要将代码从当前位置跳到全局偏移表,然后从全局偏移表中读入值,再跳到全局偏移表的值就好了。
那么,全局偏移表中的值,在链接阶段是不知道的,需要程序运行之前修改成正确的地址,这一过程就叫重定位。
还是刚刚的例子,全局偏移表中存0x00010000,重定位的时候计算加载的偏移为0x00200000-0x00000000=0x002000000,修改全局偏移表的值为0x00010000+0x002000000=0x002100000。然后程序运行的