Tiny6410之重定位代码到SRAM+4096
重定位代码
两个不同的地址概念:
对于程序而言,需要理解两个地址,一个是程序当前所处的地址,即程序运行时所处的当前地址。二是程序应该位于的运行地址,即编译程序时所指定的程序的链接地址。在Tiny6410中板子上电启动时只会从NAND Flash/MMC等启动设备中拷贝前8K的代码到SRAM中,然后跳转到SRAM中运行代码。那么问题就来了,如果我们的程序超过8K会出现什么问题呢?程序拷贝不完整运行当然出错。所以就需要我们在前8K的代码中实现将整个程序完整的拷贝到DRAM等其他更大的存储空间,然后在跳转到DRAM中运行我们的程序。这个拷贝然后跳转的过程就叫重定位。前几次的实验都是直接将.bin文件下载到DRAM中运行所以不需要重定位,而这一次,将通过NAND启动然后通过重定位的方式来运行程序。
第一步:编写连接脚本
链接脚本就是程序链接的参考文件其主要目的是描述如何把输入文件中的段(SECTION)映射到输出文件中,并控制输出文件的存储布局链接脚本的基本命令是SECTION命令,一个SECTION命令包含一个或多个段,段(SECTION)是链接脚本的基本单元,他表示输入文件中每个段是、如何防止的。
1)链接脚本中单独的(.)代表当前位置 .=0x1000;表示代码的运行地址是0x1000;
2)link.dls中的.text/.data/.bss分别是text段,data段和bss段。.text段包含的是start.o和其他代码中的所有text段,.data段包含的是其他代码中的所有.data段,.bss段包含的是其他代码中的所有.bss段
3)bss_start和bss_end分别保存bss断的的起始和结束地址,在start.S 中将会用到。
data段:
数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。
text段:
代码段(code segment/text segment)通常是用来存放程序执行代码的的一块内存区域,这部分的内存大小在程序运行前就已经确定并且内存区域通常属于只读,某些架构也代码段为可写。,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
bss段:
BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。
堆(heap):
堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
栈(stack):
栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。它是由操作系统分配的,内存的申请与回收都由OS管理。
第二步:编写代码
该章节的代码与前几次的大同小异,主要区别在start.S link.lds 和Makefile
start.S存在四个需要注意的地方
1)设置SP
将栈顶sp 指向8*1024 Nand Flash 启动时Tiny6410的内部8K的SRAM被映射到0x0而ARM默认的栈是递减的,所以可以将SP指向881024
2)增加重定位代码
首先获取_start标号的当前地址(即0x0)然后取_start的链接地址(即0x100)因为bin文件不需要保存bss段,所以拷贝长度为bss_start的地址减去_start的地址。
3)清bss段
首先获取bss_start的链接地址,然后获取bss_end 的链接地址,然后将该部分的内存清零。bss_start和bss_end的地址有Link.dls决定
4)跳转
ldr pc ,=main
由于ldr指令获取的是main函数的连接诶地址,所以执行该句后程序就跳转到0x1000+main函数的offset的地址处
//start.S
// 启动代码
.global _start _start: // 把外设的基地址告诉CPU
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,,r0,c15,c2, // 关看门狗
ldr r0, =0x7E004000
mov r1, #
str r1, [r0] // 设置栈
ldr sp, =* // 开启icaches
#ifdef CONFIG_SYS_ICACHE_OFF
bic r0, r0, #0x00001000 @ clear bit (I) I-cache
#else
orr r0, r0, #0x00001000 @ set bit (I) I-cache
#endif
mcr p15, , r0, c1, c0, // 设置时钟
bl clock_init //重定位
adr r0,_start //_start的当前地址
ldr r1, =_start //_start的连接地址
ldr r2, =bss_start
cmp r0,r1
beq clean_bss
//搬移代码
copy_loop:
ldr r3,[r0],#
str r3,[r1],#
cmp r1,r2
bne copy_loop //清bss段
clean_bss:
ldr r0, =bss_start
ldr r1, =bss_end
mov r2, #
cmp r0, r1
beq on_addr
clean_loop:
str r2, [r0],#
cmp r0, r1
bne clean_loop
on_addr:
ldr pc, =main halt:
b halt //Tiny6410Addr.h
#ifndef _Tiny6410Addr_H
#define _Tiny6410Addr_H
//GPK
#define GPKIO_BASE (0x7F008800)
#define rGPKCON0 (*((volatile unsigned long *)(GPKIO_BASE+0x00)))
#define rGPKDAT (*((volatile unsigned long *)(GPKIO_BASE+0x08))) //CLOCK
#define APLL_LOCK (*((volatile unsigned long *)0x7E00F000))
#define MPLL_LOCK (*((volatile unsigned long *)0x7E00F004))
#define EPLL_LOCK (*((volatile unsigned long *)0x7E00F008))
#define OTHERS (*((volatile unsigned long *)0x7e00f900))
#define CLK_DIV0 (*((volatile unsigned long *)0x7E00F020))
#define APLL_CON (*((volatile unsigned long *)0x7E00F00C))
#define MPLL_CON (*((volatile unsigned long *)0x7E00F010))
#define CLK_SRC (*((volatile unsigned long *)0x7E00F01C)) //GPA /uart
#define ULCON0 (*((volatile unsigned long *)0x7F005000))
#define UCON0 (*((volatile unsigned long *)0x7F005004))
#define UFCON0 (*((volatile unsigned long *)0x7F005008))
#define UMCON0 (*((volatile unsigned long *)0x7F00500C))
#define UTRSTAT0 (*((volatile unsigned long *)0x7F005010))
#define UFSTAT0 (*((volatile unsigned long *)0x7F005018))
#define UTXH0 (*((volatile unsigned char *)0x7F005020))
#define URXH0 (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0 (*((volatile unsigned short *)0x7F005028))
#define UDIVSLOT0 (*((volatile unsigned short *)0x7F00502C))
#define GPACON (*((volatile unsigned long *)0x7F008000)) #endif //main.c #include "Tiny6410Addr.h"
#define GPK4_OUT (1<<4*4)
#define GPK5_OUT (1<<4*5)
#define GPK6_OUT (1<<4*6)
#define GPK7_OUT (1<<4*7)
//延时函数
void delay()
{
volatile int i = 0x10000;
while (i--);
} int main()
{
unsigned int i = 0x10;
//将GPK4-7设置为输出
rGPKCON0 = GPK4_OUT | GPK5_OUT |GPK6_OUT |GPK7_OUT;
//跑马灯式
while ()
{
rGPKDAT = i;
i++;
if(i == 0x100)
i=0x10;
delay();
} return ;
} //link.lds
SECTIONS
{
. =0x1000;
.text :
{
start.o
*(.text)
}
. = ALIGN();
.rodata :
{
* (.rodata)
}
. =ALIGN();
.data :
{
*(.data)
}
. = ALIGN();
bss_start =.;
.bss :
{
*(.bss)
*(.common)
}
bss_end =.; }
//Makefile
link.bin: start.o main.o clock.o uart.o
arm-linux-ld -T link.lds -o link_elf $^
arm-linux-objcopy -O binary -S link_elf link.bin
arm-linux-objdump -D -m arm link_elf > link.dis %.o : %.S
arm-linux-gcc -g -c -O2 -o $@ $^ %.o : %.c
arm-linux-gcc -g -c -O2 -o $@ $^ -fno-builtin
.PHONY :clean
clean:
rm *.o *.elf *.bin *.dis -f
Tiny6410之重定位代码到SRAM+4096的更多相关文章
- Tiny6410之重定位代码到SDRAM
在上一章中,将代码重定位到了SRAM中,但是这样的做法作用不大.正确的做法的是将代码重定位到更大的主存中,即DRAM.Tiny6410的DRAM控制寄存器最多只能支持两个同一类型的芯片.每个芯片最多可 ...
- uboot重定位代码分析(转)
概述 重定位(relocate)代码将BootLoader自身由Flash复制到SDRAM,以便跳转到SDRAM执行.之所以需要进行重定位是因为在Flash中执行速度比较慢,而系统复位后总是从0x00 ...
- tiny4412 裸机程序 七、重定位代码到DRAM【转】
本文转载自:http://blog.csdn.net/eshing/article/details/37116637 一.关于DRAM 上一章我们讲解了如何对代码进行重定位,但是将代码重定位到只有25 ...
- tiny4412 裸机程序 六、重定位代码到IRAM+0x8000【转】
本文转载自:http://blog.csdn.net/eshing/article/details/37115697 一.重定向 对于程序而言,我们需要理解两个概念,一是程序当前所处的地址,即程序在运 ...
- s3c6410_uboot中的代码重定位(nand->sdram)
本文仅探讨s3c6410从nand flash启动u-boot时的代码重定位过程 参考: 1)<USER'S MANUAL-S3C6410X>第二章 MEMORY MAP 第八章 NAND ...
- u-boot移植(四)---修改前工作:代码流程分析3---代码重定位
一.重定位 1.以前版本的重定位 2.新版本 我们的程序不只涉及一个变量和函数,我们若想访问程序里面的地址,则必须使用SDRAM处的新地址,即我们的程序里面的变量和函数必须修改地址.我们要修改地址,则 ...
- s3c2440裸机-代码重定位、清bss的改进和位置无关码
1.代码重定位的改进 用ldr.str代替ldrb, strb加快代码重定位的速度. 前面重定位时,我们使用的是ldrb命令从的Nor Flash读取1字节数据,再用strb命令将1字节数据写到SDR ...
- s3c2440裸机-代码重定位(2.编程实现代码重定位)
代码重定位(2.编程实现代码重定位) 1.引入链接脚本 我们上一节讲述了为什么要重定位代码,那么怎么去重定位代码呢? 上一节我们发现"arm-linux-ld -Ttext 0 -Tdata ...
- s3c2440裸机-代码重定位(1.重定位的引入,为什么要代码重定位)
1.重定位的引入(为什么要代码重定位) 我们知道s3c2440的cpu从0地址开始取指令执行,当从nor启动时,0地址对应nor,nor可以像内存一样读,但不能像内存一样写.我们能够从nor上取指令执 ...
随机推荐
- linux中的"32位"与"64位"
linux内核学习之三:linux中的"32位"与"64位" 在通用PC领域,不论是windows还是linux界,我们都会经常听到"32位" ...
- DNN简介以及安装
开源框架DNN简介以及安装 donetnuke 是一款免费的开源cms框架,目前也有收费版,不过免费版也可以适应大家大部分的需求.我前些阵子是老板让我在20天内,做好一个官网并且发布,并且指定使用dn ...
- Web Components
Web Components是不是Web的未来 今天 ,Web 组件已经从本质上改变了HTML.初次接触时,它看起来像一个全新的技术.Web组件最初的目的是使开发人员拥有扩展浏览器标签的能力,可以 ...
- Excel开发
浅谈Excel开发:九 Excel 开发中遇到的常见问题及解决方法 Excel开发过程中有时候会遇到各种奇怪的问题,下面就列出一些本人在开发中遇到的一些比较典型的问题,并给出了解决方法,希望对大家 ...
- SQLSERVER一些公用DLL
SQLSERVER一些公用DLL的作用解释 SQLSERVER一些公用DLL的作用解释 如果你的SQLSERVER安装在C盘的话,下面的路径就是相应SQLSERVER版本的公用DLL的存放路径 S ...
- 一个人开发的html整站源码分享网站就这么上线了
项目我采用了纯静态html+动态搜索的模式,就是说详情页.主页等纯静态页面,仅搜索页面采用数据库访问搜索,搜索结果分为静态和动态,如果输入的关键字是已存在的标签就静态展示,否则就动态展示,这么做的好处 ...
- 企业架构研究总结(36)——TOGAF企业连续体和工具之企业连续体构成及架构划分
又回头看了之前文章的评论,本人也同样感慨这些文章的确像政治课本般的虚无缥缈,所以对费力看完却觉得无从下手的看官致以诚挚的歉意和理解,因为这个问题也同样困扰着笔者本人,而我能做的也只能是纸上谈兵.之前也 ...
- CentOS5、6 NFS的安装配置及mount方法
一.环境介绍: 服务器:centos 192.168.1.225 客户端:centos 192.168.1.226 二.安装: NFS的安装配置:centos 5 : yum -y install n ...
- c:翻转一个长句中的每个单词
问题: 输入:“how are you baby-- " 输出:”woh era uoy --ybab " #include<stdio. ...
- Lync Server 2013中央管理存储:自动收集配置数据失败
Lync Server 2013在安装本地配置存储到配置中央管理存储的本地副本时候提示错如信息:自动收集配置数据失败. 打开Lync Shell,输入Get-CsConfigurationStoreL ...