我们编译生成目标文件,子程序跳转时候,其实用的都是相对地址跳转,比如目标程序标号距离当前程序(pc指针的值)的偏移,然后跳转过去即可。访问全局变量也是如此,编译器分配的全局变量距离当前pc的相对偏移,访问就是了。
但是,当我们的data段(全局变量)需要搬移到其它位置时候,这个相对偏移,就出错了。
为了解决代码运行时重定位问题,我们的程序编译时候加上-fpic选项,生成的就是与地址无关的代码。编译器会在目标文件text段末尾加上一个全局符号表(程序中可以通过__rel_dyn_start引用)。所有的全局变量都会在该表进行地址登记,而程序中要访问该全局变量也从之前的偏移访问变成新的方式:先从pc通过固定偏移找到这个表中该全局变量的地址,再通过该地址访问到那个全局变量。当我们的data段(全局变量)需要搬移到其它位置时候,我们只需要写程序去更新这个表,也就是修改这里面的符号的地址(根据自己想要重定位的位置偏移更新进去),这样就能照样正常运行了。
这个代价就是,访问全局的东西时候,需要两次才能访问到数据,效率低了一点,此外,生成的目标文件也会大一些。
uboot中,就有这种骚操作,还是很有意思的。
推荐参考一本书:嵌入式C语言自我修养,讲得通俗易懂,很不错。



