重定位之前
请使用位置无关码
位置无关码,依赖于程序当前运行的PC值,进行相对的跳转,导致的结果就是,无论代码在哪,总能达到指令的正常目的,因此是位置无关的。
位置有关码,不依赖当前PC值,是绝对跳转,只有程序运行在链接地址处时,才能达到指令的正常目的,因此是位置有关系的。
以下是位置有关的,禁用
汇编
ldr r0, =main/* 获取函数名的地址,位置有关 */
ldr r0 ,=__bss_start /* 获取链接脚本里标号的地址,位置有关 */
c语言
1、全局变量是位置有关码
2、函数调用,通常是位置无关的,但有可能是位置有关的,因为如果两个函数相距32M的大小,无法用bl命令跳转
3、不要使用带初值的数组,这些初值是位置有关的
4、(这个是猜想,还没有验证) 字符串,const类型的字符串应该是存储在rodata区的,很有可能是位置有关的,所以重定位之前不要用串口打印参数
重定位的时候
Nand启动
Nandflash不可以简单的读取数据进行重定位,但是前4K代码被硬件复制到了片内4k的ram中。
所以如果重定位代码的大小小于4k,可以直接用以下代码,从片内ram拷贝代码到sdram中。
但是如果代码大小大于4K,就只能先初始化nandflash,然后从nandflash中读取代码拷贝到sdram中。
void copy2sdram(void)
{
/* 要从lds文件中获得 __code_start, __bss_start
* 然后从0地址把数据复制到__code_start
*/
extern int __code_start, __bss_start;
volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
volatile unsigned int *src = (volatile unsigned int *)0;
while (dest < end)
{
*dest++ = *src++;
}
}
nor启动
norflash可以直接读取指令来运行,所以无论代码重定位多大,都可以直接从norflash读取数据拷贝到sdram中。
如何判断是nor启动还是nand启动
int isBootFromNorFlash(void)
{
volatile int *p = (volatile int *)0;
int val;
val = *p;
*p = 0x12345678;
//因为nand启动的时候,硬件把前4k数据自动复制到片内ram中运行,所以可以直接改变ram中的数据
if (*p == 0x12345678)
{
/* 写成功, 是nand启动 */
*p = val;
return 0;
}
//但是norfalsh要写数据进去,需要很多命令和步骤,所以norflash启动的时候,在还未转移代码到sdram之前,只能读指令,不能写数据
else
{
/* NOR不能像内存一样写 */
return 1;
}
}
重定位之后
重定位之后,跳转运行请使用位置有关码,否则无法跳转到sdram运行
//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
ldr pc, =main /* 绝对跳转, 跳到SDRAM */