Tiny4412裸机程序之代码重定位初体验

从前面一节Exynos 4412的启动过程分析 ,咱们知道:一上电,exynos4412首先执行固化在IROM中的代码,iROM首先设置程序运行环境 (好比关看门狗、关中断、关MMU 、设置栈 、设置栈 、启动PLL等 ),而后根据OM引脚肯定启动设备 (NAND Flash/SD 卡/其余 ),把 BL1从里面读出存入iRAM的0x02021400地址处,最后启动 BL1; BL1从SD卡适当的位置读入14K 字节的数据,存在iRAM地址0x02023400处,因此BL2不能大于(14K – 4) 字节,这里引出了为何写这一节的缘由:若是咱们的程序很大,大于14K怎么办????html

下面咱们先来介绍两个概念:

一是程序当前所处的地址,即程序在运行时,所处的当前地址;二是程序的连接地址,即程序运行时应该位于的运行地址。编译程序时,能够指定程序的连接地址。面试

什么是重定位

对于Tiny4412而言,前面咱们已经说过:启动时BL1只会从sd等启动设备中拷贝14K的代码到IRAM中,那么当咱们的程序超过14K怎么办?那就须要咱们在前14K的代码中将整个程序完完整整地拷贝到DRAM等其余更大存储空间,而后再跳转到DRAM中继续运行咱们的代码,这个拷贝而后跳转的过程就叫重定位。服务器

本章中咱们主要学习如何重定位,可是并不会涉如何使用到DRAM,而是简单地将代码从IRAM的0x02023400处拷贝到IRAM的0x0202a000处,而后跳转到0x0202a000处继续运行咱们的代码。函数

1、程序说明

基于上一个实验的代码进行修改,修改了start,S文件以及连接脚本文件:工具

在start.S文件中增长以下代码:oop

.text
.globl _start
_start:

	/* 关闭看门狗 */
	ldr r0, =0x10060000
	mov r1, #0x0
	str r1, [r0]

	/* 启动Icache */
	mrc p15, 0, r0, c1, c0, 0
	orr r0, r0, #0x00001000	//打开ICache
	//bic r0, r0, #0x00001000 	//关闭ICache
	mcr p15, 0, r0, c1, c0, 0

	/* 重定位 - 将代码从0x02023400处拷贝到连接地址0x0202a000处(在连接脚本里指定的),并跳转到这个地址去执行 */
	adr r0, _start 		/* adr指令用于读取_start在当前的运行的物理地址,即0x02023400 */
	ldr r1, =_start 	/* 读取_start的连接地址,即0x0202a000 */
	ldr r2, =bss_start 	/* 读取bss段的起始地址,用于计算须要拷贝的字节多少 */
	cmp r0, r1
	beq clean_bss 		/* 若是r0=r1,则跳转到clean_bss,说明此时已经在连接地址处了 */

	/* 若是r0!=r1,则进行以下的拷贝 */
copy_loop:
	ldr r3, [r0], #4 		/* 源 */
	str r3, [r1], #4 		/* 目的 */
	cmp r1, r2 				/* 判断是否已经拷贝完 */
	bne copy_loop 			/* 若是没有拷贝完就继续拷贝 */

	/* 清bss段 */
clean_bss:
	ldr r0, =bss_start 		/* r0保存bss段的起始地址 */
	ldr r1, =bss_end 		/* r1保存bss段的起始地址 */
	cmp r0, r1
	beq run_on_dram 		/* 若是r0=r1,则跳转到run_on_dram,说明bss段里边没有变量 */
	mov r2, #0
clear_loop:
	str r2, [r0], #4
	cmp r0, r1
	bne clear_loop

	ldr sp, =0x02060000 

	/* 跳转 */
run_on_dram:
	ldr pc, =main 			/* 执行完这句话以后,PC就指向了main的连接地址 */

这段代码主要实现了代码重定位、清除BSS段、以及跳转到连接地址继续运行,注释说的已经很明白了,有什么的不熟悉的,你们能够留言共同探讨。学习

连接脚本reload.lds修改成以下:spa

SECTIONS {
	. = 0x0202A000;
	.text : { 
		*(.text) 
	}
	.rodata ALIGN(4) : {
		*(.rodata*)
	}
	.data ALIGN(4) : { 
		*(.data*) 
	}
	bss_start = . ;
	.bss ALIGN(4) : { 
		*(.bss) *(COMMON) 
	}
	bss_end = . ;
}

主要增长了bss段的起始bss_start及结束bss_end 的定义,这两个标号在start.S中被用到。code

2、编译、烧写、运行

1.编译htm

经过FTP或者其余工具将文件上传到服务器上去,输入make命令进行编译将获得reload.bin文件。

2.烧写

将SD卡插入电脑,并让VmWare里的Ubuntu识别出来,而后执行以下命令:

sudo ./sd_fusing.sh /dev/sdb ../8_reload/reload.bin

将SD卡插入Tiny4412开发板,上电,你会看到和上一节的运行效果同样(由于咱们没有修改LED的显示效果,只是修改了程序的运行地址,这个对外是看不出区别的)。

3、反汇编文件分析

将反汇编文件reload.dis,从服务器上下载下来,咱们进行简单分析一下:

从上图能够看出,程序的连接地址确实是咱们在链接脚本里指定的0x0202a000

咱们再来看看跳转的那条指令;

202a060:	e59ff010 	ldr	pc, [pc, #16]	; 202a078 <run_on_dram+0x18>

将当前PC的值加上24后的地址的内容赋给PC,即:

0x202a060 + 8 +16 = 0x0202a078

将0x0202a078这个地址的值赋给PC

0x0202a0b0这个地址正是main函数的入口地址。

我在本身的开发板上面试验成功。有兴趣的小伙伴能够自行试验。

相关文章
相关标签/搜索