欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

(6)代码重定位一(IRAM内部)

程序员文章站 2022-03-02 10:12:18
一、背景两个概念:运行地址和链接地址。运行地址:程序当前所处的地址,就是程序被下载到的地址。链接地址:程序运行时应该位于的运行地址。对于 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