嵌入式学习笔记(18)代码重定位实战 下篇

嵌入式学习笔记(18)代码重定位实战 下篇_第1张图片

adr和ldr伪指令的区别

ldr和adr都是伪指令,区别是ldr是长加载、adr是短加载。

adr指令加载的是运行时地址;ldr指令加载的是链接地址。

(通过反汇编文件可以深入分析adr和ldr的区别)

重定位(代码拷贝)

重定位就是汇编代码中的copy_loop函数,代码的作用是使用循环结构来逐句复制代码到链接地址。

复制的源地址是iSRAM的0xd0020010,目标地址是iSRAM的0xd0024000,复制长度是bss_start减去_start。

复制的长度就是真个重定位需要重定位的长度,也就是整个程序代码段+数据段的长度。

bss段(0初始化的全局变量)不需要重定位。

清bss段

清除bss段是为了满足C语言运行时要求(C语言要求显示初始化为0的全局变量或者未显示初始化的全局变量值为0,实际上C语言编译器就是通过清bss段来实现C语言的这个特性的)。一般情况下我们的程序是不需要清bss段的(C语言编译器会自动帮程序添加一段头程序,这段程序会在main函数之前运行,负责清除bss)。但是在代码重定位了之后,因为编译器帮我们附加的代码只是帮我们清除了运行时地址那一份代码中的bss,而未清除重定位地址处开头的那一份代码中的bss,所以重定位之后需要自己去清除bss。

长跳转

清理完bss段后重定位就结束了,当前的情况就是:

(1)当前运行地址还是0xd0020010开头的(重定位之前的)那一份代码中运行着

(2)此时iRAM中已经有了2份代码,1份在0xd0020010开头,另一份在0xd0024000开头的位置。

然后就要长跳转了。

嵌入式学习笔记(18)代码重定位实战 下篇_第2张图片

//重定位

// adr指令用于加载_start当前运行地址

adr r0, _start   // adr加载时就叫短加载

// ldr指令用于加载_start的链接地址:0xd0024000

ldr r1, =_start  // ldr加载时如果目标寄存器是pc就叫长跳转,如果目标寄存器是r1等就叫长加载

// bss段的起始地址

ldr r2, =bss_start // 就是我们重定位代码的结束地址,重定位只需重定位代码段和数据段即可

cmp r0, r1 // 比较_start的运行时地址和链接地址是否相等

beq clean_bss // 如果相等说明不需要重定位,所以跳过copy_loop,直接到clean_bss

// 如果不相等说明需要重定位,那么直接执行下面的copy_loop进行重定位

// 重定位完成后继续执行clean_bss。



// 用汇编来实现的一个while循环

copy_loop:

ldr r3, [r0], #4        // 源

str r3, [r1], #4         // 目的   这两句代码就完成了4个字节内容的拷贝

cmp r1, r2 // r1和r2都是用ldr加载的,都是链接地址,所以r1不断+4总能等于r2

bne copy_loop



// 清bss段,其实就是在链接地址处把bss段全部清零

clean_bss:

ldr r0, =bss_start

ldr r1, =bss_end

cmp r0, r1 // 如果r0等于r1,说明bss段为空,直接下去

beq run_on_dram // 清除bss完之后的地址

mov r2, #0

clear_loop:

str r2, [r0], #4 // 先将r2中的值放入r0所指向的内存地址(r0中的值作为内存地址),

cmp r0, r1 // 然后r0 = r0 + 4

bne clear_loop



run_on_dram:

// 长跳转到led_blink开始第二阶段

ldr pc, =led_blink // ldr指令实现长跳转



// 从这里之后就可以开始调用C程序了

//bl led_blink // bl指令实现短跳转



// 汇编最后的这个死循环不能丢

b .

 嵌入式物联网的学习之路非常漫长,不少人因为学习路线不对或者学习内容不够专业而错失高薪offer。不过别担心,我为大家整理了一份150多G的学习资源,基本上涵盖了嵌入式物联网学习的所有内容。点击这里扫码进群领资料,0元领取学习资源,让你的学习之路更加顺畅!记得点赞、关注、收藏、转发哦!

你可能感兴趣的:(嵌入式学习笔记,嵌入式,编程,学习,笔记,嵌入式实时数据库,嵌入式硬件,51单片机,iot)