【S3C2440】第13課、代碼重定位之課堂學習筆記


1、第1節:打印結果:aaaaaaaaaabcdefghijklmnopqrstuvwxyaz{|}
可知:1)當撥碼開關從Nand調到Nor再調到Nand時,之前的程序運行結果依然存在且程序接着之前的進程繼續運行
2)全局變量的改變在Nor中無用,在Nand中有作用,例如(同一程序):Nand: Aa1Bb2Cc3...    Nor: Aa1Aa1Aa1...


程序只能從Nandflash/Norflash啓動,SRAM/SDRAM之於Nandflash/Norflash爲輔助角色,其功能爲重定位複製存儲數據段甚至代碼段

 

Norflash不需要設置,即可直接調用; 而SDRAM需要設置,然後才能調用。

 

Nandflash前4K是複製到SRAM中,然後在Nand檔運行; 超過4k就會運行崩潰,需要設置Nandflash控制器;

====================================================================
2、第13課的第二節問題:
在於main()函數中while(1)打印:ABCDE...
while(sdram_test() == 1)時,持續輸出一個不變字符達不到預期目的, 如:UUUU...
解答:在判斷或執行sdram_test()函數時,[0x30000000]及之後的100000個字節的內存被該函數賦值重新裝數;
當只有一個字符自加結果打印時,只會輸出被修改後的數,而主程序要實現字符自加的目的將永遠不能實現
當有多個字符自加結果打印時,每次打印兩個被修改的數,而主程序要實現字符自加的目的將永遠不能實現
=====================================================================
3、問題:關於鏈接腳本使用的問題,第13課第5節008程序:
SECTIONS
{
. = 0x30000000;
. = ALIGN(4);
.text 0 : {*(.text);}
. = ALIGN(4);
.rodata : {*(.rodata);}
. = ALIGN(4);
.data : {*(.data);}
. = ALIGN(4);
_bss_start = . ;
.bss :
{
*(.bss)  *(.COMMON);
}
_end = . ;
}
#...
int g_i = 0;
int g_j = 0xabcdef12;
int g_k = 0x12;
int g_l = 12;
volatile unsigned char g_char1 = 'A';
volatile unsigned char g_char2 = 'a';
volatile unsigned char g_char3 = '1';
int main(void){...}
程序下載到Nor的打印結果:
0xffffffff
0xabcdef12
0x00000012
0x0000000c
Aa1Aa1Aa1Aa1Aa1
程序下載到Nand/或去0後的打印結果:
0x00000000
0xabcdef12
0x00000012
0x0000000c
Aa1Bb2Cc3Dd4
問題:不自加的原因已經找到,鏈接腳本中,.text從0開始,整個程序的重定位失效,通過查看.dis可知;
把鏈接腳本中的.text 0中的0去掉之後,下載到Nor,運行就正常了。但是,沒修改前.bss爲什麼不可以清零?
問題反映到【Linux嵌入式維基百科羣 】,回答如下:
百問科技~韋東山(1402284892)  11:43:18
如果使用的編譯器不一樣 比如更高版本 可能出現不可預料的問題
=======================================================================
4、問題代碼: cmp r1, r2
ble clean
當 r1==r2 時,若.bss段末字節不是整對齊4字節的末字節,該整對齊4字節其餘字節空間是不是也會被清0?乃至段間空閒字節空間如何處理呢?
答:1)理論上會的,.bss段結尾後是_end即有效程序的結尾,即使_end不是4字節的尾字節也無所謂,但一般.bss段放在最後,所以多清0也無所謂;
2)如果是別的段,如:.text, .rodata, .data段,則不會。因爲所有讀寫操作都是以4字節爲單位,且從所有段起始地址就是以4字節對齊的,
.data段(甚至別的段)與下一段之間,即使有全局變量在.data段最後一個字節,但其在該段的位置必然小於等於該段的末地址,且必然小於下一個4字節的
起始地址,而末地址所在的4字節必然服從讀寫操作。
3)對於在一個段實際有效的結束字節和下一段的開始字節間的空間,是程序未用到的字節空間(1-3字節),是程序不用的空間,任意操作無所謂?
雖然任意改寫對程序沒有影響,但是訪問的話,得到的將是不可預料的數,應該讓程序慎重運行在可控的內存空間。
關於問題3第一小問的解決意見(修改如下):
1- sdram.lds:
. = ALIGN(4);
_end = . ;
2- cmp r1, r2
blt clean
代入程序運行結果:結果見問題5結果。
========================================================================
5、問題代碼:bl sdram_init
/* 所有程序重定位 */
mov r1, #0 //程序在.bin文件中的地址,即加載地址
ldr r2, =_start //第一條指令運行時的地址
ldr r3, =_bss_start //程序結束地址
cpy:
ldr r4, [r1]
str r4, [r2]
add r1, r1, #4
add r2, r2, #4
cmp r2, r3
ble cpy
問題及分析:重定位的代碼,除了.text, .rodata, .data段,由於ble是判斷 r2 <= r3 時即執行cpy; 
因此,當cpy到 _bss_start 地址時,r2=r3 仍成立,仍然要複製.bss段的頭4字節空間的內容到SDRAM;
修改意見:ble 改爲 blt(小於執行xxx)
代入程序運行結果:

經問題4/5的修改意見修改之後,打印效果和修改之前一模一樣,實驗例程路徑:relocate>008_2。

 

======================================================================

6、關於外部變量__code_start替換爲_start的使用驗證

/* 重定位全部程序.text, .rodata, .data段 */
void copy_sdram(void)
{
extern int __code_start, _bss_start, _start; //_start在.text中; __code_start, _bss_start,在sdram.lds中;
volatile unsigned int * src = (volatile unsigned int *)0; //加載起始地址
//volatile unsigned int * dest = (volatile unsigned int *)&__code_start; //1號:重定位起始地址
volatile unsigned int * dest = (volatile unsigned int *)&_start; //2號:重定位起始地址
volatile unsigned int * end = (volatile unsigned int *)&_bss_start; //重定位起始地址

while(dest < end)
{
*dest++ = *src++;
}
}
經驗證,1號2號的打印結果一樣,均爲正常打印; 
2號的反彙編爲:
| Disassembly of section .text: |
| 30000000 <_start>: |



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章