3.5.1任务:在iSRAM中将代码从0xd0020010重定位到0xd0024000
注解:本练习对代码本身运行无实际意义,我们做这个重定位纯粹是为了练习重定位技能。但是某些情况重定位就是必须的,譬如在uboot中。
3.5.2思路
(1)通过链接脚本将代码链接到0xd0024000(链接地址)
(2)使用dnw下载时将bin文件下载到0xd0020010(运行时地址)
当代码链接地址设置为0xd0024000时,隐含意思就是我这个代码将来必须在0xd0024000位置才能正确执行。如果运行时地址不是这个地址就会出问题(除非是PIC代码)。重定位就是:在PIC执行完之前(在代码中第一句位置有关码执行之前)必须将整个代码搬移到0xd0024000位置去执行。
(3)代码执行时通过代码前段的少量PIC将整个代码搬移到0xd0024000。
(4)使用一个长跳转指令跳转到0xd0024000处的代码继续执行,重定位完成。
长跳转:跳转指令通过给PC(r15)赋一个新值来完成代码段的跳转执行。长跳转指的是跳转到的地址和当前地址差异比较大,跳转的范围比较广。
当我们执行完代码重定位后,实际上在SRAM中有2份代码的镜像(一份是我们下载到0xd0020010处开头的,另一份是重定位代码复制到0xd0024000处开头的),这两份内容完全相同,仅仅地址不同。重定位之后使用ldr pc, =led_blink这句长跳转直接从0xd0020010处代码跳转到0xd0024000开头的那一份代码的led_blink函数处去执行。(实际上此时在SRAM中有2个led_blink函数镜像,两个都能执行,如果短跳转bl led_blink则执行的就是0xd0020010开头的这一份,如果长跳转ldr pc, =led_blink则执行的是0xd0024000开头处的这一份)。这就是短跳转和长跳转的区别。
当链接地址和运行时地址相同时,短跳转和长跳转实际效果是一样的;但是当链接地址不等于运行时地址时,短跳转和长跳转就有差异了。这时候短跳转实际执行的是运行时地址处的那一份,而长跳转执行的是链接地址处那一份。
总结:重定位实际就是在运行地址处执行一段位置无关码PIC,让这段PIC(也就是重定位代码)从运行地址处把整个程序镜像拷贝一份到链接地址处,完了之后使用一句长跳转指令从运行地址处直接跳转到链接地址处去执行同一个函数(led_blink),这样就实现了重定位之后的无缝连接。
嵌入式物联网的学习之路非常漫长,不少人因为学习路线不对或者学习内容不够专业而错失高薪offer。不过别担心,我为大家整理了一份150多G的学习资源,基本上涵盖了嵌入式物联网学习的所有内容。点击这里扫码进群领资料,0元领取学习资源,让你的学习之路更加顺畅!记得点赞、关注、收藏、转发哦!