Tiny4412裸机程序之代码重定位初体验
2018-02-19 16:07
197 查看
从前面一节Exynos 4412的启动过程分析 ,我们知道:一上电,exynos4412首先执行固化在IROM中的代码,iROM首先设置程序运行环境 (比如关看门狗、关中断、关MMU 、设置栈 、设置栈 、启动PLL等 ),然后根据OM引脚确定启动设备 (NAND Flash/SD 卡/其他 ),把 BL1从里面读出存入iRAM的0x02021400地址处,最后启动 BL1; BL1从SD卡适当的位置读入14K 字节的数据,存在iRAM地址0x02023400处,所以BL2不能大于(14K – 4) 字节,这里引出了为什么写这一节的原因:如果我们的程序很大,大于14K怎么办????
本章中我们主要学习如何重定位,但是并不会涉如何使用到DRAM,而是简单地将代码从IRAM的0x02023400处拷贝到IRAM的0x0202a000处,然后跳转到0x0202a000处继续运行我们的代码。
在start.S文件中增加如下代码:
这段代码主要实现了代码重定位、清除BSS段、以及跳转到链接地址继续运行,注释说的已经很明白了,有什么的不熟悉的,大家可以留言共同探讨。
链接脚本reload.lds修改为如下:
主要增加了bss段的起始bss_start及结束bss_end 的定义,这两个标号在start.S中被用到。
通过FTP或者其他工具将文件上传到服务器上去,输入make命令进行编译将得到reload.bin文件。
2.烧写
将SD卡插入电脑,并让VmWare里的Ubuntu识别出来,然后执行如下命令:
将SD卡插入Tiny4412开发板,上电,你会看到和上一节的运行效果一样(因为我们没有修改LED的显示效果,只是修改了程序的运行地址,这个对外是看不出区别的)。
从上图可以看出,程序的链接地址确实是我们在连接脚本里指定的0x0202a000
我们再来看看跳转的那条指令;
将当前PC的值加上24后的地址的内容赋给PC,即:
将0x0202a078这个地址的值赋给PC
0x0202a0b0这个地址正是main函数的入口地址。
我在自己的开发板上面试验成功。有兴趣的小伙伴可以自行试验。
下面我们先来介绍两个概念:
一是程序当前所处的地址,即程序在运行时,所处的当前地址;二是程序的链接地址,即程序运行时应该位于的运行地址。编译程序时,可以指定程序的链接地址。什么是重定位
对于Tiny4412而言,前面我们已经说过:启动时BL1只会从sd等启动设备中拷贝14K的代码到IRAM中,那么当我们的程序超过14K怎么办?那就需要我们在前14K的代码中将整个程序完完整整地拷贝到DRAM等其他更大存储空间,然后再跳转到DRAM中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。本章中我们主要学习如何重定位,但是并不会涉如何使用到DRAM,而是简单地将代码从IRAM的0x02023400处拷贝到IRAM的0x0202a000处,然后跳转到0x0202a000处继续运行我们的代码。
一、程序说明
基于上一个实验的代码进行修改,修改了start,S文件以及链接脚本文件:在start.S文件中增加如下代码:
.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修改为如下:
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中被用到。
二、编译、烧写、运行
1.编译通过FTP或者其他工具将文件上传到服务器上去,输入make命令进行编译将得到reload.bin文件。
2.烧写
将SD卡插入电脑,并让VmWare里的Ubuntu识别出来,然后执行如下命令:
sudo ./sd_fusing.sh /dev/sdb ../8_reload/reload.bin
将SD卡插入Tiny4412开发板,上电,你会看到和上一节的运行效果一样(因为我们没有修改LED的显示效果,只是修改了程序的运行地址,这个对外是看不出区别的)。
三、反汇编文件分析
将反汇编文件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函数的入口地址。
我在自己的开发板上面试验成功。有兴趣的小伙伴可以自行试验。
相关文章推荐
- Tiny4412裸机程序之代码重定位初体验
- 几种典型程序Button处理代码的定位
- 使用MAP文件快速定位程序崩溃代码行
- MS-VC 使用MAP文件快速定位程序崩溃代码行
- 地图定位程序代码
- 使用MAP文件快速定位程序崩溃代码行
- 程序异常立刻退出,如何定位关键代码位置
- 程序崩溃 没有代码 无法定位 Dr Watson Windbg
- 使用MAP文件快速定位程序崩溃代码行
- 使用MAP文件快速定位程序崩溃代码行(转)
- 如何快速的定位程序中某个功能对应的代码?
- 调试release版本程序dump时出现的代码定位不准确问题
- android判断程序是否前台显示---及判断屏幕是否是亮的----附赠BAIDU定位的工具类实现代码
- 必杀技公布——用特征码定位关键代码,秒杀MFC程序
- Linux 使用core file文件快速定位程序崩溃代码行
- 使用MAP文件快速定位程序崩溃代码行
- 使用MAP文件快速定位程序崩溃代码行
- 【分享】必杀技公布——用特征码定位关键代码,秒杀MFC程序
- 2013 Mac Air 装Win7双系统问题-安装程序无法创建新的分区,也无法定位系统 & Windows无法安装所需的文件,错误代码0x80070570
- 几种典型程序Button处理代码的定位