重定位代码
两个不同的地址概念:
对于程序而言,需要理解两个地址,一个是程序当前所处的地址,即程序运行时所处的当前地址。二是程序应该位于的运行地址,即编译程序时所指定的程序的链接地址。在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的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。