任务
在SRAM中将代码从0xd0020010重定位到0xd0024000
任务解释:本来代码是运行在 0xd0020010的,因为一些原因我们又希望代码实际运行在 0xd0024000 。这时候就需要重定位了。
注解
:本练习对代码本身运行无实际意义,通过这个去熟悉重定位这个技能。但某些情况重定位是必须的,譬如在uboot中。
思路
1. 通过链接脚本将代码链接到0xd0024000
2. dnw下载时,将bin文件下载到0xd0020010
第1点 + 第2点,就保证了:代码实际下载运行在
0xd0020010
,但是却被链接在0xd0024000
从而为重定位奠定了基础。当我们把代码链接地址设置为0xd0024000时,实际隐含意思就是我这个代码必须放在0xd0024000这个地址才能正确执行。如果实际运行地址不是这个地址就要出事(除非代码是PIC位置无关码),当以上都明白之后,就明白重定位的作用就是:在PIC(位置无关码)执行完之前(或在代码中第一句位置有关码执行之前)必须将整个代码搬移到链接的地址(0xd0024000)位置去执行,这就是重定位
3. 代码执行时通过代码前段的少量位置无关码将整个代码搬移到0xd0024000
4. 使用一个长跳转 跳转到0xd0024000处的代码继续执行 重定位完成
长跳转
:首先这句代码是一句跳转指令(ARM中的跳转指令就是类似于分支指令 B、BL等作用的指令)跳转指令通过给PC(r15)赋一个新值来完成代码段的跳转执行,当我们执行完代码重定位后,实际上在SRAM中有两份代码的镜像(一份是我们下载到0xd0020010处开头的,另一份是重定位复制的0xd0024000处开头的),这两份内容完全相同,仅仅地址不同。重定位之后 使用ldr pc,=led_blink
这句长跳转直接从0xd0020010处代码跳转到0xd0024000开头的那一份代码的led_blink函数处去执行。(实际上此时在SRAM中有2个 led_blink函数镜像,两个都能执行,如果短跳转bl led_blink
则执行的就是0xd0020010开头的这一份, 如果长跳转 `ldr pc,=led_blink则执行的是0xd0024000开头处的这一份)这就是长跳转和短跳转的区别
当链接地址和运行地址一样时,长跳转和短跳转实际效果是一样的;但是当链接地址和运行地址(下载烧入的地址)不一样时,长跳转和短跳转就有差异了。这时候短跳转实际执行的是运行地址处的那一份,而长跳转则执行的是链接地址的那一份
总结:
重定位实际就是在运行地址处执行一段
PIC(位置无关码)也就是重定位代码
把运行地址处的整个程序镜像拷贝一份到链接地址处,完了之后使用一句长跳转指令从运行地址处直接跳转到链接地址处去执行同一个函数(led_blink);这样就实现了重定位之后的无缝衔接。