重定位
- 为什么需要重定位?
- 重定位是什么?
- 怎么实现重定位?
环境
1、s3c2440裸板
2、Linux version 4.15.0
首先
1、为什么需要重定位?
s3c2440启动有两种方式: a、nand 启动 b、nor启动
nor | nand |
---|---|
可以像内存一样读,不能像内存一样写,因此当代码存在全局变量,静态变量时,不能有效的修改这些变量的值 | 上电 硬件将nand代码拷贝前4k到sram中,从sram开始执行,如果代码大于4K,必须在前4k实现能够将代码拷贝到sdram中执行的功能 |
因此以上都需要重定位功能:如下图
2. 重定位是什么?
百度百科:重定位就是把程序的逻辑地址空间变换成内存中的实际物理地址空间的过程。它是实现多道程序在内存中同时运行的基础。重定位有两种,分别是动态重定位与静态重定位;
个人理解:就是吧烧写的代码从烧写地址拷贝到内存,并且当操作这个值得时候可以去内存中操作不影响程序的运行;即从烧写地址=>运行地址
3、怎么实现重定位?
举例:
设置一个初值不为0的全局变量,然后调用函数修改该变量的值,之后串口打印出修改后的值,分别烧写到nand 和nor 观察现象;
main.c
//省略了头文件引入
unsigned char Bchar = 'A'; //全局变量
int main(void)
{
uart0_init(); //串口初始化
while(1)
{
putchar(Bchar);
Bchar++;
delay(100000);
}
return 0;
}
start.S 汇编启动文件
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0]
/*设置时钟*/
ldr r0, =0x4C000000
ldr r1, =0xFFFFFFFF
str r1, [r0]
//cpu 工作为异步模式
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
ldr r0, =0x4C000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]
/*设置栈*/
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
moveq sp, #4096 /* nand启动 */
streq r0, [r1]
/*
重定位代码:
ldr r1, =0x30000030
ldr r2, =0xf80
ldr r3, [r2]
str r3, [r1]
*/
结果:
烧写到nand :如下图会递增打印
烧写到nor中: 一直打印’A‘
解决办法:
在start.S添加如下代码上面已经注释了:
重定位代码:
ldr r1, =0x30000030 //内存空间 sdram中地址
ldr r2, =0xf80 //全局变量B_char地址,通过反汇编查看;
ldr r3, [r2]
str r3, [r1]
编译文件的时候使用连接脚本:
SECTIONS {
.text 0 : {*(.text)} //指定地址为0 开始存放代码段,所有文件代码段放在这里
.rodata : {*(.rodata)} //所有文件只读段放在代码段之后
.data 0x30000020 : AT(0xf80){*(.data)} //指定所有文件数据段 加载地址为0xf80(即烧写到0xf80的位置, 运行的时候在0x30000020处操作)
.bss : {*(.bss) *.commen}
}
这样;烧写到nand 和nor 上都可以递增打印字符’A’ 了