1. 程式人生 > >重定位的理解

重定位的理解

一 、程式碼的組成

程式至少包含:程式碼段+資料段

程式碼段:.text

資料段:一般的全域性變數,初值不為0的經過初始化的全域性變數

        如:char g_char ='A';    //初值為A的字元型全域性變數

rodata:const的全域性變數,只讀資料段

bss:初值為0,或者沒有初值的全域性變數,不儲存在bin檔案中

     如:int g_A =0;     //

初值為0的整形全域性變數

           int g_B;         //無初值的整形全域性變數

commen:註釋,不儲存在bin檔案中

關於bss段和comment段為什麼不儲存在bin檔案中,可以這樣來理解,如果我們的程式碼中有非常多的全域性變數(比如100萬個char型變數),如果這些資料都儲存在bin檔案中,那麼我們的bin檔案得有多大,顯然這是不可能的。

所以,一般地,在連結指令碼中,我們都需要指出這幾個段在記憶體中的分配情況。如下所示:

                                               

二、必須知道的幾個概念

1、連結地址和執行地址。

①執行地址,顧名思義就是程式執行的時候的地址,也就是你用工具將程式碼下載到RAM的那個地址,也叫載入地址。

②連結地址,由連結指令碼指定的地址。為什麼需要連結指令碼指定地址呢?你想一下,在c語言程式設計中,當我們需要呼叫一個A函式的時候,編譯器是怎麼找到這個A函式?編譯器肯定是知道它被放在哪裡才可以找到它。那就是連結指令碼的作用,連結指令碼其實在程式被執行之前都已經指定A函式一個地址編號,以後所有的函式呼叫我們都會去這個地址編號那裡尋找A函式。有點類似於c語言的指標變數。

2、什麼是重定位?

重定位就是程式碼搬移到你想要的地址,本來程式是執行在執行地址處的,

你可以通過重定位搬移到連結地址處。

3、為什麼需要重定位?

大部分的程式是不需要重定位的,但是有時候需要進行重定位,最常見的例子就是

我們的UBOOT,因為我們的UBOOT有200多KB,但是我們開始BL0的地方只有96KB。

所以我們需要在96KB之前進行重定位,使開發板能夠進行重定位。

三、重定位之前的狀態

重定位決定了pc取指令的地址,但是很顯然SoC晶片剛剛上電時,重定位還沒有實現,SoC需要執行一段程式碼來實現重定位,所以這時PC指標並沒有指向重定位地址的地方,那麼這個過程是如何實現的呢?

 上電後,PC指向哪裡?

對於任何一種SoC晶片來說,上電後PC指標的位置是有硬體設計決定的,一般地,對於cortex-M系列核心的晶片,上電後PC指標都為0,指向0地址處。

對於nand啟動,0地址對應片內sram,因為nand控制器上電後自動將nand中的前4k大小拷貝到了sram中,所以此時sram中存在程式碼(即nand中前4K程式碼),核心就可以取指令並執行了。

對於nor啟動,0地址對應nor晶片,我們已經將程式下載到nor上了,所以此時pc也可以取指令並執行了。