tiny4412 裸机程序 六、重定位代码到IRAM+0x8000【转】

本文转载自:http://blog.csdn.net/eshing/article/details/37115697

一、重定向

对于程序而言,我们需要理解两个概念,一是程序当前所处的地址,即程序在运行时,所处的当前地址;二是程序的链接地址,即程序运行时应该位于的运行地址。编译程序时,可以指定程序的链接地址。对于Tiny4412而言,启动时只会从MMC/sd等启动设备中拷贝前16K的代码到IRAM中,那么当我们的程序超过16K怎么办?那就需要我们在前16K的代码中将整个程序完完整整地拷贝到DRAM等其他更大存储空间,然后再跳转到DRAM中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。

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

二、程序说明

完整代码见目录5_link_0x8000,该目录下的代码与上一章的代码的差别在于start.S和使用了

链接脚本link.lds,我们首先分析link.lds。

1. link.lds

什么是链接脚本?链接脚本就是程序链接时的参考文件,其主要目的是描述如何把输入文件中的段(SECTION)映射到输出文件中,并控制输出文件的存储布局。链接脚本的基本命令式SECTIONS命令,一个SECTIONS命令内部包含一个或多个段,段(SECTION)是链接脚本的基本单元,它表示输入文件中的某个段是如何放置的。

链接脚本的标准格式如下:

SECTIONS

{

sections-command

sections-command

}

下面我们配合link.lds进行具体讲解:

SECTIONS

{

. = 0x02028000;

.text : {

start.o

* (.text)

}

.data : {

* (.data)

}

bss_start = .;

.bss : {

* (.bss)

}

bss_end = .;

}

1)  在链接脚本中,单独的点号(.)代表了当前位置,. =0x02028000;表示程序的链接地址是00x02028000;

2)  link.lds中的.text 、 .data 、 .bss分别是text段、data段、bss段的段名(这些段名并不是固定的,是可以随便起的)。.text 段包含的内容是start.o 和其余代码中所有的text段;.data段包含的内容是代码中所有的data段;.bss段包含的内容是代码中所有的bss段。

3)  bss_start和bss_end保存的是bss段的起始地址和结束地址,在start.S中会被用到。

下面解释一下什么是data、text、bss段:

1)  data段:数据段(datasegment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

2)  text段:代码段通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

3)  bss段:指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文BlockStarted by Symbol的简称。当我们的程序有全局变量是,它是放在bss段的,由于全局变量默认初始值都是0,所有我们需要手动清bss段。

2. start.S

在start.S中,我们初始化时钟后,增加了3个步骤:

第一步重定位,代码如下:

// _start当前所位于的地址

adr r0, _start  

// _start的链接地址

ldr r1, =_start  

ldr r2, =bss_start

cmp r0, r1

beq clean_bss

copy_loop:

ldr r3, [r0], #4

str r3, [r1], #4

cmp r1, r2

bne copy_loop

首先需要知道的是,adr指令获取的值是代码当前位于的地址,而ldr指令获取的值是代码的链接地址。再来看代码,代码里首先获得_start标号的当前地址(即0x02020010),然后获取_start标号的链接地址(即0x02028000),因为bin文件中不需要保存bss段,所有拷贝的代码长度为bss_start的运行地址-_start的运行地址,使用copy_loop进行拷贝。

第二步清bss,代码如下:

ldr r0, =bss_start        

ldr r1, =bss_end

cmp r0, r1

beq run_on_dram

mov r2, #0

clear_loop:

str r2, [r0], #4

cmp r0, r1

bne clear_loop

首先获得bss段的起始地址(即bss_start),然后获得bss段的结束地址(即bss_end),最后使用clear_loop将bss段所位于的内存清0,bss_start和bss_end的定义位于link.lds。

第三步跳转,代码如下:

run_on_dram:   

ldr pc, =main

由于ldr 指令获取的是main函数的链接地址,所以执行ldrpc, =main 后,程序就跳转到

0x02020000+main函数的offset的地址处了。

三、完整的烧写过程

已将SD卡插入电脑,假设Linux识别了SD卡,其识别号为sdb。执行下面命令:

# chmod 777 –R 5_link_0x8000

# cd 5_link_0x8000

# make

# cd sd_fuse

# make

# ./ fast_fuse /dev/sdb

四、上电实验

将sd卡插入Tiny4412中,选择sd卡启动,然后上电,可以看到以下现象:

LED正常闪烁,该现象与前面章节的代码的运行效果一模一样,但是程序的运行过程却有了很大的区别。通过本章的学习,我们已经知道了如何对代码进行重定位,这为我们下一章节将代码重定位到DRAM奠定了基础。

备注:说明一下,代码已上传到我的资源里,我要了两个下载分,不好意思,我的资源分太少了,我得赚点,我相信我的程序是绝对能运行的,觉得值就去下载。

 
0
原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7248961.html