欢迎光临散文网 会员登陆 & 注册

13.5代码重定位_代码重定位与位置无关码

2020-08-21 14:48 作者:韦东山  | 我要投稿

        一个程序,由代码段、只读数据段、数据段、bss段等组成。 程序一开始可以烧在Nor Flash上面,运行时代码段仍可以在Nor Flash运行,但对于数据段,就必须把数据段移到SDRAM中,因为只要在SDRAM里面,数据段的变量才能被写操作,把程序从一个位置移动到另一个位置,把这个过程就称为重定位。 前面的例子,我们只是重定位了数据段,这里我们再尝试重定位整个代码。


先梳理下把整个程序复制到SDRAM需要哪些技术细节:
1. 把程序从Flash复制到运行地址,链接脚本中就要指定运行地址为SDRAM地址;
2. 编译链接生成的bin文件,需要在SDRAM地址上运行,但上电后却必须先在0地址运行,这就要求重定位之前的代码与位置无关(是位置无关码);

参考Uboot修改链接脚本: 

        现在我们写的这个链接脚本,称为一体式链接脚本,对比前面的分体式链接脚本区别在于代码段和数据段的存放位置是否是分开的。

例如现在的一体式链接脚本的代码段后面依次就是只读数据段、数据段、bss段,都是连续在一起的。 分体式链接脚本则是代码段、只读数据段,中间相关很远之后才是数据段、bss段。


我们以后的代码更多的采用一体式链接脚本,原因如下:
1. 分体式链接脚本适合单片机,单片机自带有flash,不需要再将代码复制到内存占用空间。而我们的嵌入式系统内存非常大,没必要节省这点空间,并且有些嵌入式系统没有Nor Flash等可以直接运行代码的Flash,就需要从Nand Flash或者SD卡复制整个代码到内存;
2. JTAG等调试器一般只支持一体式链接脚本; 


修改start.S段 

将修改后的代码重新编译烧写在Nor Flash上,上电运行。 对本代码的启动情况进行分析:

Chapter13 lesson5 001.jpg

在生成的bin文件里,代码保存的位置是0x30000000。随后烧写到NOR Flash的0地址,但代码的结构没有变化。之后再重定位到SDRAM。


查看反汇编: 

可以看到现在变成了bl 30000478,但两个的机器码eb000106都是一样的,机器码一样,执行的内容肯定都是一样的。 因此这里并不是跳转到显示的地址,而是跳转到: pc + offset,这个由链接器决定。


假设程序从0x30000000执行,当前指令地址:0x3000005c ,那么就是跳到0x30000478;如果程序从0运行,当前指令地址:0x5c 调到:0x00000478

跳转到某个地址并不是由bl指令所决定,而是由当前pc值决定。反汇编显示这个值只是为了方便读代码。

重点: 反汇编文件里, B或BL 某个值,只是起到方便查看的作用,并不是真的跳转。 


怎么写位置无关码?

  1. 使用相对跳转命令 b或bl;

  2. 重定位之前,不可使用绝对地址,不可访问全局变量/静态变量,也不可访问有初始值的数组(因为初始值放在rodata里,使用绝对地址来访问);

  3. 重定位之后,使用ldr pc = xxx,跳转到/runtime地址;

写位置无关码,其实就是不使用绝对地址,判断有没有使用绝对地址,除了前面的几个规则,最根本的办法看反汇编。

因此,前面的例子程序使用bl命令相对跳转,程序仍在NOR/sram执行,要想让main函数在SDRAM执行,需要修改代码: 


13.5代码重定位_代码重定位与位置无关码的评论 (共 条)

分享到微博请遵守国家法律