什么是重定位
简单来说就是把程序从内存的一个位置复制到另一个位置。
重定位的重要性
若s3c2440使用Nand Flash启动,则CPU会将Nand Flash的前4k拷贝到s3c2440 soc内部的SRAM。如果程序没有重定位代码,则只能运行Nand flash前4k的程序。
若s3c2440使用Nor Flash启动,则CPU无法修改Nor Flash内存中的数据。如果程序没有重定位代码,则会因为无法修改全局变量、静态变量的值导致程序运行出错。
链接脚本
链接脚本的格式如下:
SECTIONS
{
sectname start BLICK(align) (NOLOAD) : AT( ldadr )
{ contents } >region :phdr =fill
...
}
主要会用到的格式如下:
SECTIONS
{
.sectname : AT( ldadr )
{ contents }
...
}
.sectname | 自定义段名 |
---|---|
start | 起始地址:运行时的地址(runtime address)或者重定位的地址(relocate address) |
ldadr | 加载地址:load address(不声明此地址,会默认是runtime address) |
content | 内容:可以直接指定某一个文件(如start.o),也可以指定所有的(如 *(.text)),也可以指定某一个文件之外的所有段(如start.o *(.text) |
具体的代码如下:
SECTIONS
{
. = 0x30000000; #表示relocate addr从0x3000000(sdram的基地址)开始
__code_start = .; #声明一个变量用于重定位,其值等于0x30000000(该变量的地址就是他的值)
. = ALIGN(4); #4字节对齐
.text : #一个标号
{
*(.text) #表示.text里的内容是所有的text段
}
. = ALIGN(4);
.rodata : { *(.rodata) } #只读数据段
. = ALIGN(4);
.data : { *(.data) } #初值不为0的全局变量段
. = ALIGN(4);
__bss_start = .; #声明一个变量用于之后清除bss和comment段,也用于重定位
.bss : { *(.bss) *(.COMMON) } #bss段和comment段
_end = .; #用于清除bss和comment段的变量
}
重定位函数:
void relocate_to_sdram(void)
{
/* 要从lds文件中获得 __code_start, __bss_start
* 然后从0地址把数据复制到__code_start
*/
extern int __code_start, __bss_start; //在lds文件里的变量需要extern声明
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++;//循环复制代码
}
}
void clean_bss(void)
{
/* 要从lds文件中获得 __bss_start, _end
*/
extern int _end, __bss_start;
volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
volatile unsigned int *end = (volatile unsigned int *)&_end;
while (start <= end)
{
*start++ = 0;//循环删除bss段和comment段
}
}