关于裸机程序重定位的问题,我对基于jz2440的开发板上的重定位程序进行了分析,总结以下学习过程
在开始之前,先简单说一下2440开发板的两种启动过程
1、nand flash启动,将编译好的程序烧入开发板的nand flash进行启动,这时CPU内部会自动
将nand flash内部的代码前4k拷贝到CPU片内SRAM上执行,所以此时CPU执行的0地址为
片内SRAM上的地址。
2、nor flash启动,将程序烧录进norflash进行启动的话,CPU执行代码的0地址为nor flash内的地址
也就是说,CPU从nor flash中取指,执行。
那么为什么需要程序的重定位呢?
如果从nor flash中启动的话,nor flash不能像内存那样进行简单的写操作,那么程序中的一些变量就行出错, 如果是nand flash中启动的话,因为nand flash中前4K的代码会被拷贝到片内的SRAM中去,那么当程序大于4K的话也会 执行出错,所以会有代码重定位的需求。
关于链接脚本的语法和作用在此不做解析,但要知道一点,生成的bin文件的格式是和链接脚本有关的,
比如链接脚本对应
SECTIONS
{
.= 0x30000000;
.= ALIGN(4);
.text :
{
*(.text)
}
.= ALIGN(4);
.rodata : { *(.rodata)
.= ALIGN(4);
.data : { *(.data) }
.= ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
_end = .;
}
根据链接脚本生成的bin文件的格式如下
此时该程序如果从nor flash中启动执行的话,它在nor flash中的位置如下
它被烧录进nor flash的0地址,CPU从0地址处开始取指,执行,当执行到我们的重定位代码处开始进行代码的重定位
/* 重定位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
上面的0就是nor flash中的加载地址,_start是程序的运行地址(0x300000000),从这里进行拷贝,将程序拷贝到SDRAM中运行地址处,结果如下
跳转到SDRAM中执行程序,如果执行程序从nand flash中启动的话,如果程序小于4K,此时的重定位程序直接从SRAM中拷贝到SDRAM中去,拷贝程序和nor flash的程序没有差别,如果程序大于4k的话就必须从nand flash中进行拷贝,此时就需要专门的nand flash操作程序去拷贝,关于nand flash的程序在另一篇文章中介绍,这里也只是总结一下我对整个重定位的理解,也在初级学习阶段,如果有不对的地方请指正,谢谢。