要解释重定位,首先需要理解程序是怎么链接的。程序链接的时候可以通过链接脚本将程序链接到指定地址上,可以链接成地址相关码也可以链接成地址无关码。 顾名思义,地址相关码就是把程序链接到指定地址上,在嵌入式开发中经常用到地址相关码的编译。由于嵌入式的板子资源有限,需要规划内存的使用,就需要合理规划bios、操作系统、嵌入式软件的地址。地址无关码就是程序可以被加载到任意地址上,但是程序的指令编译之后就是固定的,在函数调用、全局变量的使用的时候如何正确定位到指定地址上呢? 举一个例子,如果我们链接的地址是0x00000000,被调用的函数被链接到0x00010000上,如果指令的逻辑直接跳转到0x00010000,那就是地址相关码。如果要把程序加载到0x00200000上,那被调用的函数就被加载到0x002100000上,要想让指令正确运行,就需要做重定位。 常用的重定位技术是,将所有的全局符号放在全局偏移表中,在elf文件中就是。got段,如果涉及动态库的话就是。got。plt段。全局偏移表中放着全局符号的地址,由于链接的过程中知道全局偏移表的位置,只需要将代码从当前位置跳到全局偏移表,然后从全局偏移表中读入值,再跳到全局偏移表的值就好了。 那么,全局偏移表中的值,在链接阶段是不知道的,需要程序运行之前修改成正确的地址,这一过程就叫重定位。 还是刚刚的例子,全局偏移表中存0x00010000,重定位的时候计算加载的偏移为0x002000000x000000000x002000000,修改全局偏移表的值为0x000100000x0020000000x002100000。然后程序运行的时候指令跳转到全局偏移表读到的地址就是0x002100000,那么函数就能调用的正确的地址了。全局变量的重定位类似。 但是,需要格外注意的是,最近几年国产化盛行。龙芯的mips指令是一个特例。简单介绍一下,mips本身不是龙芯发明的,但是现在找遍全球的芯片厂商,可能也就是龙芯在用mips指令集。 mips指令集是一个定长的指令集,跟x86有很大区别。mips有两个非常关键的寄存器gp还有t9,有做这方面的同学需要要自己研究下。 mips指令集也是非常有意思,函数的前两行指令非常关键,也可以用来做一些意想不到的设计。如果你想把数据段和代码段分开放,可以研究研究这两行指令。对于有些特殊的行业的无扰加载程序非常友好。 mips的常量的分页机制也非常有意思,有兴趣的同学可以研究下,虽然就重定位来说,常量如果被放在。rodata段,其重定位的方法和全局变量完全一样,但是这种分页机制可以让我在许多其他方面的设计上借鉴。 要想完全将明白重定位,可能需要写一本书,我这里知识大概介绍一下相关知识,需要了解的同学可能需要大量的研究和实践。 祝好。