13.2代碼重定位_鏈接腳本的引入與簡單測試
前面程序運行,發(fā)現(xiàn)從Nand Flash啟動和從Nor Flash啟動表現(xiàn)是不一樣的。
設(shè)置成Nand Flash啟動沒有問題 顯示ABCDE...
設(shè)置成NOor Flash啟動則顯示AAA...
這是什么原因呢?
假如現(xiàn)在是Nor啟動:

Nor Flash就被認為是0地址,g_Char被放在0x700后面。CPU上電后從0地址開始執(zhí)行,它能讀取Nor Flash上的代碼,打印出A,當進行g(shù)_Char++的時候,寫操作操作無效,下次讀取的數(shù)據(jù)仍然是A。
假如現(xiàn)在是Nand啟動:

上電后,Nand Flash前4K代碼就被自動的復(fù)制到SRAM里面,SRAM是CPU認為的0地址。CPU上電后從0地址開始執(zhí)行,它讀取SRAM上的代碼,并g_Char++修改變量,下次讀取的數(shù)據(jù)就依次增加了。
為了解決Nor Flash里面的變量不能寫的問題,我們把變量所在的數(shù)據(jù)段放在SDRAM里面,看行不行。
修改Makefile ?指定數(shù)據(jù)段為0x30000000 -Tdata 0x30000000:?
arm-linux-ld -Ttext 0 -Tdata 0x30000000 ?start.o led.o uart.o init.o main.o -o sdram.elf
這樣的話編譯出來的bin文件 從0地址 到 0x30000000地址 文件大小有700多MB,代碼段和數(shù)據(jù)段直接有間隔,稱之為黑洞。

解決黑洞有兩個辦法:
第一個方法
把數(shù)據(jù)段的g_Char和代碼段靠在一起;
燒寫在Nor Flash上面;
運行時把g_char(全局變量)復(fù)制到SDRAM,即0x3000000位置(重定位);
第二個方法
讓文件直接從0x30000000開始,全局變量在0x3......;
燒寫Nor Flash上 0地址處;
運行會把整個代碼段數(shù)據(jù)段(整個程序)從0地址復(fù)制到SDRAM的0x30000000(重定位);
這兩個方法的區(qū)別是前者只重定位了數(shù)據(jù)段,后者重定位了數(shù)據(jù)段和代碼段。?
第一種辦法如何實現(xiàn) 修改Makefile的代碼段地址,使用鏈接腳本sdram.lds指定。?
#arm-linux-ld -Ttext 0 -Tdata 0x30000000 ?start.o led.o uart.o init.o main.o -o sdram.elf arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf
鏈接腳本的語法:?

我們需要依次排列 代碼段、只讀數(shù)據(jù)段、數(shù)據(jù)段、.bss段、.common。
其中數(shù)據(jù)段放在0x700,但運行時在0x3000000:?

重新編譯后燒寫bin文件,發(fā)現(xiàn)啟動后顯示亂碼。原因是我們從0x30000000處獲取g_Char,但在這之前,并沒有在0x30000000處準備好數(shù)據(jù)。因此需要重定位數(shù)據(jù)段,將0x700的數(shù)據(jù)移動到0x30000000處,在start.S加入:?

上面的這種方法,只能復(fù)制0x700處的一位數(shù)據(jù),不太通用,下面寫一個更加通用的復(fù)制方法:
鏈接腳本修改如下:

修改start.S?
