重定位代碼
兩個不同的地址概念:
對于程序而言,需要理解兩個地址,一個是程序當前所處的地址,即程序運行時所處的當前地址。二是程序應該位于的運行地址,即編譯程序時所指定的程序的鏈接地址。在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的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。