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的地址处
1 //start.S 2 // 启动代码 3 .global _start 4 5 _start: 6 7 // 把外设的基地址告诉CPU 8 ldr r0, =0x70000000 9 orr r0, r0, #0x13 10 mcr p15,0,r0,c15,c2,4 11 12 // 关看门狗 13 ldr r0, =0x7E004000 14 mov r1, #0 15 str r1, [r0] 16 17 // 设置栈 18 ldr sp, =8*1024 19 20 // 开启icaches 21 #ifdef CONFIG_SYS_ICACHE_OFF 22 bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache 23 #else 24 orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache 25 #endif 26 mcr p15, 0, r0, c1, c0, 0 27 28 // 设置时钟 29 bl clock_init 30 31 //重定位 32 adr r0,_start //_start的当前地址 33 ldr r1, =_start //_start的连接地址 34 ldr r2, =bss_start 35 cmp r0,r1 36 beq clean_bss 37 //搬移代码 38 copy_loop: 39 ldr r3,[r0],#4 40 str r3,[r1],#4 41 cmp r1,r2 42 bne copy_loop 43 44 //清bss段 45 clean_bss: 46 ldr r0, =bss_start 47 ldr r1, =bss_end 48 mov r2, #0 49 cmp r0, r1 50 beq on_addr 51 clean_loop: 52 str r2, [r0],#4 53 cmp r0, r1 54 bne clean_loop 55 on_addr: 56 ldr pc, =main 57 58 halt: 59 b halt 60 61 //Tiny6410Addr.h 62 #ifndef _Tiny6410Addr_H 63 #define _Tiny6410Addr_H 64 //GPK 65 #define GPKIO_BASE (0x7F008800) 66 #define rGPKCON0 (*((volatile unsigned long *)(GPKIO_BASE+0x00))) 67 #define rGPKDAT (*((volatile unsigned long *)(GPKIO_BASE+0x08))) 68 69 //CLOCK 70 #define APLL_LOCK (*((volatile unsigned long *)0x7E00F000)) 71 #define MPLL_LOCK (*((volatile unsigned long *)0x7E00F004)) 72 #define EPLL_LOCK (*((volatile unsigned long *)0x7E00F008)) 73 #define OTHERS (*((volatile unsigned long *)0x7e00f900)) 74 #define CLK_DIV0 (*((volatile unsigned long *)0x7E00F020)) 75 #define APLL_CON (*((volatile unsigned long *)0x7E00F00C)) 76 #define MPLL_CON (*((volatile unsigned long *)0x7E00F010)) 77 #define CLK_SRC (*((volatile unsigned long *)0x7E00F01C)) 78 79 80 81 //GPA /uart 82 #define ULCON0 (*((volatile unsigned long *)0x7F005000)) 83 #define UCON0 (*((volatile unsigned long *)0x7F005004)) 84 #define UFCON0 (*((volatile unsigned long *)0x7F005008)) 85 #define UMCON0 (*((volatile unsigned long *)0x7F00500C)) 86 #define UTRSTAT0 (*((volatile unsigned long *)0x7F005010)) 87 #define UFSTAT0 (*((volatile unsigned long *)0x7F005018)) 88 #define UTXH0 (*((volatile unsigned char *)0x7F005020)) 89 #define URXH0 (*((volatile unsigned char *)0x7F005024)) 90 #define UBRDIV0 (*((volatile unsigned short *)0x7F005028)) 91 #define UDIVSLOT0 (*((volatile unsigned short *)0x7F00502C)) 92 #define GPACON (*((volatile unsigned long *)0x7F008000)) 93 94 #endif 95 96 //main.c 97 98 #include "Tiny6410Addr.h" 99 #define GPK4_OUT (1<<4*4) 100 #define GPK5_OUT (1<<4*5) 101 #define GPK6_OUT (1<<4*6) 102 #define GPK7_OUT (1<<4*7) 103 //延时函数 104 void delay() 105 { 106 volatile int i = 0x10000; 107 while (i--); 108 } 109 110 int main() 111 { 112 unsigned int i = 0x10; 113 //将GPK4-7设置为输出 114 rGPKCON0 = GPK4_OUT | GPK5_OUT |GPK6_OUT |GPK7_OUT; 115 //跑马灯式 116 while (1) 117 { 118 rGPKDAT = i; 119 i++; 120 if(i == 0x100) 121 i=0x10; 122 delay(); 123 } 124 125 return 0; 126 } 127 128 //link.lds 129 SECTIONS 130 { 131 . =0x1000; 132 .text : 133 { 134 start.o 135 *(.text) 136 } 137 . = ALIGN(4); 138 .rodata : 139 { 140 * (.rodata) 141 } 142 . =ALIGN(4); 143 .data : 144 { 145 *(.data) 146 } 147 . = ALIGN(4); 148 bss_start =.; 149 .bss : 150 { 151 *(.bss) 152 *(.common) 153 } 154 bss_end =.; 155 156 } 157 //Makefile 158 link.bin: start.o main.o clock.o uart.o 159 arm-linux-ld -T link.lds -o link_elf $^ 160 arm-linux-objcopy -O binary -S link_elf link.bin 161 arm-linux-objdump -D -m arm link_elf > link.dis 162 163 %.o : %.S 164 arm-linux-gcc -g -c -O2 -o $@ $^ 165 166 %.o : %.c 167 arm-linux-gcc -g -c -O2 -o $@ $^ -fno-builtin 168 .PHONY :clean 169 clean: 170 rm *.o *.elf *.bin *.dis -f
View Code
转载于:https://www.cnblogs.com/chenshikun/p/5840128.html
Tiny6410之重定位代码到SRAM+4096相关推荐
- Tiny6410之重定位代码到SDRAM
在上一章中,将代码重定位到了SRAM中,但是这样的做法作用不大.正确的做法的是将代码重定位到更大的主存中,即DRAM.Tiny6410的DRAM控制寄存器最多只能支持两个同一类型的芯片.每个芯片最多可 ...
- uboot重定位代码分析(转)
概述 重定位(relocate)代码将BootLoader自身由Flash复制到SDRAM,以便跳转到SDRAM执行.之所以需要进行重定位是因为在Flash中执行速度比较慢,而系统复位后总是从0x00 ...
- tiny4412 裸机程序 六、重定位代码到IRAM+0x8000【转】
本文转载自:http://blog.csdn.net/eshing/article/details/37115697 一.重定向 对于程序而言,我们需要理解两个概念,一是程序当前所处的地址,即程序在运 ...
- tiny4412 裸机程序 六、重定位代码到IRAM+0x8000
一.重定向 对于程序而言,我们需要理解两个概念,一是程序当前所处的地址,即程序在运行时,所处的当前地址:二是程序的链接地址,即程序运行时应该位于的运行地址.编译程序时,可以指定程序的链接地址.对于Ti ...
- tiny4412 裸机程序 七、重定位代码到DRAM【转】
本文转载自:http://blog.csdn.net/eshing/article/details/37116637 一.关于DRAM 上一章我们讲解了如何对代码进行重定位,但是将代码重定位到只有25 ...
- uboot为什么要重定位/代码拷贝?
参考自:https://www.cnblogs.com/Cqlismy/p/12152400.html 必看.这个老哥写的uboot启动的博客非常棒,感谢. 还有https://blog.csdn.n ...
- 重定位代码Repair
此类指令都为6个字节 大致试验结果如下: 第一个字节跟操作类型相关,第二个字节跟寄存器相关,后面四个字节为地址 第二个字节高四位必须为8,9,A,B四个中的一个,低四位必为5和D中的一个,产生8种排列 ...
- S5PV210体系结构与接口04:代码重定位 SDRAM初始化
目录 1. C语言环境初始化 1.1 C语言运行所需环境 1.2 初始化栈 1.2.1 栈的概念 1.2.2 栈的作用 1.2.3 如何初始化 1.3 初始化bss段 1.3.1 bss段的作用 1. ...
- Windows PE第6章 栈与重定位表
第六章 栈与重定位表 本章主要介绍栈和代码重定位.站和重定位表两者并没有必然的联系,但都和代码有关.栈描述的是代码运行过程中,操作系统为调度程序之间相互调用关系,或临时存放操作数而设置的一种数据结构. ...
最新文章
- go http的按序号发送,按序号接收
- Java 异常处理的误区和经验总结
- 红米电流电压测试软件,你也是27W家族?Redmi K20 Pro充电测试
- strcpy会覆盖原来的吗_幽默你真的会了吗?原来可以这么简单
- 如何用excel筛选相似内容_Excel中如何将两组数据的相同内容进行快速筛选配对...
- DBMS_SPACE包的使用
- python 切片_全面解读Python高级特性切片
- CSS3学习笔记总结,你值得拥有(呕心沥血之作,涵盖CSS3所有知识点)
- 前端布局之网格gird布局(简单易懂)
- 显示桌面图标不见了的解决方法
- react入门教程案例井字棋(包含改进代码)
- 微软原版win10系统启动盘的使用
- 面试题大汇总华为面试题
- couchbase php,从PHP SDK设置后,Couchbase视图不会更新
- 【数据结构】循环链表(circular linked list) 双向链表(doubly linked list)
- Java中的Collections.sort()
- 数据挖掘➡谈谈为什么学?
- PC微信hook学习笔记(一)—— 获取个人信息
- 手机日常使用技巧、和手机停机如何免费上网 。好多大家不知道的功能 不看后悔哦
- 前端不让浏览器自动填充账号密码
热门文章
- 广告投放管理平台 oython源码_【直播】全新腾讯广告投放管理平台如何帮助广告主乘风破浪...
- linux消息通信无法接收,求助!Linux基于UDP通信失败,server接收不到消息???...
- 【Linux】【开发环境】【RHEL】开发环境搭建系列之十一——Linux系统下搭建基于vim的C/C++ IDE开发环境
- 计算机图形学应用基础考试,计算机图形学基础期末考试试题.docx
- 简述计算机数控系统的工作原理,计算机数控系统复习题-20210321010307.docx-原创力文档...
- 在Linux服务器上如何开启安全的SNMP代理
- 【数据结构】— 『队列』的实现以及LeetCode队列练习题
- 全网最全JavaScript正则表达式( 校验数字和字母)
- 第一篇博客----试水
- IBM Verse On-Premises 1.0.7发布