嵌入式-ARM-学习总结(4):重定位
一、重定位
一般学习一个知识点,需要知道是什么,在什么情况下用,怎么用。这三步走,即可把一个知识点吃透。
那重定位是什么呢?
1.重定位是什么
重定位实际上就是在运行一段位置无关码PIC,让这段PIC(也就是重定位代码)从运行地址处把整个程序镜像拷贝一份到链接地址处,完了之后使用一句长跳转指令从运行地址处,直接跳转到链接地址去执行同一个函数,这样就实现了重定位之后的无缝连接。
这个里面出现一个名词位置无关码,这是什么呢?
2.位置无关编码与位置有关编码
位置无关编码(PIC,postition independent code):回避源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关。
**位置有关编码:**汇编源码编码成二进制可执行程序后和内存地址是有关的。
对比:位置无关代码要好一些,适应性强,放在哪里都能正常运行;位置有关代码就必须运行在链接时指定的地址上,适应性差。位置无关码有一些限制,不能完成所有功能,有时候不得不使用位置有关代码。
3.为什么需要重定位呢
因为对于有些时候,链接地址和运行地址必须是不同地址。而且还不能全部使用位置无关代码,所以需要使用重定位来实现分散加载。(这里的分散加载相当于一种手工的重定位)
4.链接地址和运行地址
链接地址:链接时指定的地址(指定方式:Makefile中用-Ttext,或者链接脚本)
运行地址:程序实际运行时的地址(指定方式:由实际运行时被加载到内存的哪个位置说了算)
5.重定位的使用
练习:在SRAM中将代码从0xd0020010重定位到0xd0024000。
思路:
第一步:通过链接脚本将代码链接到0xd0024000
第二步:dnw下载时将bin文件下载到0xd0020010
第三步:代码执行时通过代码前段的少量位置无关码将整个代码搬移到0xd0024000
第四步:使用一个长跳转到0xd0024000处的代码继续执行,重定位完成
第一步加上第二步,就保证了:代码实际下载运行在0xd0020010,但是却被链接在0xd0024000。从而为重定位奠定了基础。
当我们把代码链接地址设置为0xd0024000时,实际隐含意思就是我这个代码将来必须放在0xd0024000位置才能正确执行。如果实际运行地址不是这个地址就要出事(除非代码是PIC位置无关码),当以上都明白了后,就知道重定位代码的作用就是:在PIC执行完之前(在代码中第一句位置有关码执行之前)必须将整个代码搬移到0xd0024000位置去执行,这就是重定位。
长跳转和短跳转的区别:
当链接地址和运行地址相同时,短跳转和长跳转实际效果是一样的;但是当链接地址不等于运行地址时,短跳转和长跳转就有差异了。这时候短跳转实际执行的是运行地址处的那一份,而长跳转执行的是链接地址处那一份。
6.例子:
//start.s文件
#define WTCON 0xE2700000
#define SVC_STACK 0xd0037d80
.global _start // 把_start链接属性改为外部,这样其他文件就可以看见_start了
_start:
// 第1步:关看门狗(向WTCON的bit5写入0即可)
ldr r0, =WTCON
ldr r