(6)代码重定位一(IRAM内部)
程序员文章站
2022-06-09 20:42:17
一、背景两个概念:运行地址和链接地址。运行地址:程序当前所处的地址,就是程序被下载到的地址。链接地址:程序运行时应该位于的运行地址。对于 S5PV210 而言,启动时只会从 NAND Flash/sd 等启动设备中拷贝前 16K 的代码到 IRAM中,那么当我们的程序超过 16K 怎么办?那就需要我们在前 16K 的代码中将整个程序完完整整地拷贝到 DRAM 等其他更大存储空间,然后再跳转到 DRAM 中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。位置无关代码:运行地址与链接地址可以不同...
一、背景
两个概念:运行地址和链接地址。
运行地址:程序当前所处的地址,就是程序被下载到的地址。
链接地址:程序运行时应该位于的运行地址。
对于 S5PV210 而言,启动时只会从 NAND Flash/sd 等启动设备中拷贝前 16K 的代码到 IRAM中,那么当我们的程序超过 16K 怎么办?那就需要我们在前 16K 的代码中将整个程序完完整整地拷贝到 DRAM 等其他更大存储空间,然后再跳转到 DRAM 中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。
位置无关代码:运行地址与链接地址可以不同。
位置有关代码:运行地址与链接地址必须相同。
链接脚本:链接脚本就是程序链接时的参考文件,其主要目的是描述如何把输入文件中的(SECTION) 映射到输出文件中, 并控制输出文件的存储布局。 链接脚本的基本命令式 SECTIONS命令,一个SECTIONS 命令内部包含一个或多个段,段(SECTION)是链接脚本的基本单元,它表示输入文件中的某个段是如何放置的。
段:分为.text、.data、.bss、和用户自定义段。
.text段:代码段有叫文本段,用来存放代码。
.data段:数据段用来放初始化过的全局变量数据。
.bss段:用来存放程序中未初始化的全局变量的一块内存区域。
二、代码
1、start.S
/*
* 代码:重定位代码到IRAM0xD0024000
* 日期:2020.7.11
* 作者:glass love
*
*/
//要开icache就将 CONFIG_SYS_ICACHE_OFF写为1,关则写为0
#define CONFIG_SYS_ICACHE 1
.globl _start
_start:
/**********************关看门狗*******************************/
//通过查阅数据手册知道控制看门狗开关的寄存器是:
//Watchdog Timer Control Register (WTCON, R/W, Address =0xE2700000 )
//WTCON寄存器的bit[0]位是启用或禁用复位信号的看门狗定时器输出位
//1为启用,0为禁止
//因此只需要往WTCON中写入0x0即可
ldr r0, =0x00000000
ldr r1, =0xE2700000
str r0, [r1]
/**********************开icache*********************************/
//打开icache可以提高运行速度
//读出协处理器cp15的c1的值到r0中
mrc p15, 0, r0, c1, c0, 0
#if CONFIG_SYS_ICACHE
//将cp15协处理器的bit[12]置一(开icache)
orr r0, r0, #0x00001000
#else
//将cp15协处理器的bit[12]清零(关icache)
bic r0, r0, #0x00001000
#endif
//将r0中的值写入到cp15协处理器的c1中
mcr p15, 0, r0, c1, c0, 0
/***********************设置栈****************************/
//IROM 里的固定代码设置的 sp 就等于 0xD003_7D80,
//所以我们设置栈一般就指向0xD003_7D80,以调用c函数
ldr sp, =0xD0037D80
/*************************重定位***************************/
//adr短加载,加载_start的地址,即_start的当前地址
adr r0, _start
//ldr长加载,加载_start的链接地址
ldr r1, =_start
//加载bss_start的链接地址
ldr r2, =bss_start
//比较r0和r1是否相同
cmp r0, r1
beq clear_bss
//复制代码到链接地址
copy_loop:
ldr r3, [r0], #4 //源代码
str r3, [r1], #4 //目标代码
cmp r1, r2 //只用复制到bss_start处就可以了
bne copy_loop
//清bss段
clear_bss:
ldr r0, =bss_start
ldr r1, =bss_end
cmp r0, r1
beq run_dram
ldr r2, =0x0
clear_loop:
str r2, [r0], #4
cmp r0, r1
bne clear_loop
//跳转到链接地址中的led函数处
run_dram:
ldr pc, =led_blink
//汇编死循环
b .
2、link.lds
SECTIONS
{
. = 0xD0024000; /*指定链接地址*/
.text : {
start.o /*表示start.o排在代码段的最开始*/
* (.text) /*(.text)表示后面的顺序随意*/
}
.data : {
* (.data)
}
bss_start = .; /*将bss段的起始地址赋给bss_start,以方便外部使用该地址*/
.bss : {
* (.bss)
}
bss_end = .; /*bss_end同上*/
}
3、Makefile
led_link.bin: start.o led.o
arm-linux-ld -Tlink.lds -o led_link.elf $^
arm-linux-objcopy -O binary led_link.elf led_link.bin
arm-linux-objdump -D led_link.elf > led_link_elf.dis
gcc mkv210_image.c -o mk210
./mk210 led_link.bin 210.bin
%.o : %.S
arm-linux-gcc -o $@ $< -c -nostdlib
%.o : %.c
arm-linux-gcc -o $@ $< -c -nostdlib
clear:
rm *.o *.elf *.bin *.dis mk210 -f
其余代码较上一节均为变化。
本文地址:https://blog.csdn.net/weixin_47123600/article/details/107286634