历史上的今天
今天是:2024年09月10日(星期二)
2021年09月10日 | S3c2440代码重定位详解5---代码重定位与位置无关码
2021-09-10 来源:eefocus
一个程序,由代码段、只读数据段、数据段、bss段等组成。
程序一开始可以烧在Nor Flash上面,运行时代码段仍可以在Nor Flash运行,但对于数据段,就必须把数据段移到SDRAM中,因为只要在SDRAM里面,数据段的变量才能被写操作,把程序从一个位置移动到另一个位置,把这个过程就称为重定位。
先梳理下把整个程序复制到SDRAM需要哪些技术细节:
把程序从Flash复制到运行地址,链接脚本中就要指定运行地址(Runtime addr)为SDRAM地址;
编译链接生成的bin文件,需要在SDRAM地址上运行,但上电后却必须先在0地址运行,这就要求重定位之前的代码与位置无关(是位置无关码写成);
参考Uboot修改链接脚本:
SECTIONS
{
. = 0x30000000;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
_end = .;
}
现在我们写的这个链接脚本,称为一体式链接脚本,对比前面的分体式链接脚本区别在于代码段和数据段的存放位置是否是分开的。
例如现在的一体式链接脚本的代码段后面依次就是只读数据段、数据段、bss段,都是连续在一起的。
分体式链接脚本则是代码段、只读数据段,中间相关很远之后才是数据段、bss段。
我们以后的代码更多的采用一体式链接脚本,原因如下:
分体式链接脚本适合单片机,单片机自带有flash,不需要再将代码复制到内存占用空间。而我们的嵌入式系统内存非常大,没必要节省这点空间,并且有些嵌入式系统没有Nor Flash等可以直接运行代码的Flash,就需要从Nand Flash或者SD卡复制整个代码到内存;
JTAG等调试器一般只支持一体式链接脚本;
修改start.S段
/* 重定位text, rodata, data段整个程序 */
mov r1, #0
ldr r2, =_start /* 第1条指令运行时的地址 */
ldr r3, =__bss_start /* bss段的起始地址 */
cpy:
ldr r4, [r1]
str r4, [r2]
add r1, r1, #4
add r2, r2, #4
cmp r2, r3
ble cpy
/* 清除BSS段 */
ldr r1, =__bss_start
ldr r2, =_end
mov r3, #0
clean:
str r3, [r1]
add r1, r1, #4
cmp r1, r2
ble clean
bl main
halt:
b halt
将修改后的代码重新编译烧写在Nor Flash上,上电运行。
对本代码的启动情况进行分析:

在生成的bin文件里,代码保存的位置是0x30000000。随后烧写到NOR Flash的0地址,但代码的结构没有变化。之后再重定位到SDRAM
查看反汇编:
3000005c: eb000106 bl 30000478 30000060: e3a01000 mov r1, #0 ; 0x0 30000064: e59f204c ldr r2, [pc, #76] ; 300000b8 <.text+0xb8> 30000068: e59f304c ldr r3, [pc, #76] ; 300000bc <.text+0xbc> 这里的bl 30000478不是跳转到30000478,这个时候sdram并未初始化; 为了验证,我们做另一个实验,修改连接脚本sdram.lds, 链接地址改为0x32000478,编译,查看反汇编: 3000005c: eb000106 bl 30000478 30000060: e3a01000 mov r1, #0 ; 0x0 30000064: e59f204c ldr r2, [pc, #76] ; 300000b8 <.text+0xb8> 30000068: e59f304c ldr r3, [pc, #76] ; 300000bc <.text+0xbc> 可以看到现在变成了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执行,需要修改代码 //bl main /*bl相对跳转,程序仍在NOR/sram执行*/ ldr pc, =main/*绝对跳转,跳到SDRAM*/
史海拾趣
|
坛子里好像越来越多的人对此产生了兴趣。我最初的读卡器是用CM200开发的,硬件开发没有什么特别的,CM200内部带地址锁存,接口很方便,其它的按照datasheet照搬就行了。关键是天线板的设计,尺寸形状都会影响,而我觉得这些定了之后,设计的关键又 ...… 查看全部问答> |
|
程序模拟了音乐的七个音皆(do,re,me,fa,so,la,si),包括低音,中音及高音. 有兴趣的朋友可下载程序到target board一试,或到以下网站观看示范片段. http://v.youku.com/v_show/id_XMTQwMjI0MjI0.html 附件是作者提供的Qtopia应用程序,感兴趣的 ...… 查看全部问答> |
|
本帖最后由 paulhyde 于 2014-9-15 09:30 编辑 在哈尔滨工程大学六年,我在学校电子创新实验室呆了四年,这四年里创新实验室给我提供了良好的学习环境和完善的实验设备;在与众多电子爱好者的交流中,使我学到了更多的专业知识;在学校老师们的教 ...… 查看全部问答> |
|
请问如何设计一个类似BTS功能的设备,可以取得无线L3的消息? 请问如何从空口中提取L3的信号,应该使用何种模块?? TC35系列芯片虽然可以处理GSM协议栈,但不知道是否可以从其端口取得空口的的消息? 现有如下思路如下: 天线 + ??1 + TC ...… 查看全部问答> |
|
我在linux系统下编译u-boot生成u-boot、u-boot.bin和u-boot.srec三个文件,编译uClinux(2.4.x版)后生成image.ram、image.rom 和 romfs.img。请问用什么工具烧写u-boot和uClinux呢?应该烧哪些文件呢?有没有相关的文档?我之前移植ucos等都是用H- ...… 查看全部问答> |
|
1. 用硬件定时器编写程序,设置时、分、秒定时器,分别对应的地址为:4000H、4002H、4004H,晶振频率为12MHZ(用8096编写) 2.C08__2 MODULE MAIN $INCLUDE(8096.INT) PORT EQU OFFA8H ...… 查看全部问答> |
|
我用电脑并口与51单片机通信的时候,采取的是EPP1.9模式,发现老是nWait=1,不知道什么原因, 有没有这方面的前辈指导一下。感谢不尽。 源码如下: #include /* inp, outp */ #include /* kbhit() et al */ #incl ...… 查看全部问答> |




