一、必須知道的幾個概念。 1、鏈接地址和運行地址。 ①運行地址,顧名思義就是程式運行的時候的地址,也就是你用工具將代碼下載到RAM的那個地址,也叫載入地址。 ②鏈接地址,由鏈接腳本指定的地址。為什麼需要鏈接腳本指定地址呢?你想一下,在c語言編程中,當我們需要調用一個A函數的時候,編譯器是怎麼找到這個 ...
一、必須知道的幾個概念。
1、鏈接地址和運行地址。
①運行地址,顧名思義就是程式運行的時候的地址,也就是你用工具將代碼下載到RAM的那個地址,也叫載入地址。
②鏈接地址,由鏈接腳本指定的地址。為什麼需要鏈接腳本指定地址呢?你想一下,在c語言編程中,當我們需要調用一個A函數的時候,編譯器是怎麼找到這個A函數?編譯器肯定是知道它被放在哪裡才可以找到它。那就是鏈接腳本的作用,鏈接腳本其實在程式被執行之前都已經指定A函數一個地址編號,以後所有的函數調用我們都會去這個地址編號那裡尋找A函數。有點類似於c語言的指針變數。
2、位置有關碼與位置無關碼。
①位置有關碼,就是這句代碼的執行正確與否還需要取決於當前的地址,也就是說跟地址已經綁定了的,例如:ldr PC, _main,就是PC指針必須跳轉到_main(函數名就是一個地址)這個地址去,代碼執行成功與否就相當於受到了這個地址的約束,假如這個地址的內容不存放_main這個函數,就會出錯了。
②位置無關碼,就是這句代碼在哪裡運行都可以的,跟所處的地址無關,跟位置有關碼相反。
二、重定位需要理解的一些問題。
1、鏈接地址跟運行地址不同的情況下會出現什麼情況?
答:以上面舉的函數A為例,當鏈接地址跟運行地址不同的時候,假如鏈接地址是0x1000,運行地址(載入地址)是0x0000,鏈接腳本指定函數A將來是要存放到(基地址+偏移量)=0x1000+0x0001=0x1001地址的,但是程式在下載的時候卻把這個程式下載到0x0000,所以函數A的地址實際上是存放在(基地址+偏移量)=0x0000+0x0001=0x0001這個地址的。當程式運行到一行位置有關碼例如:ldr PC, A ,編譯器首先就會按照鏈接腳本指定的A的那個地址0x1001尋找A函數,但是因為載入地址跟鏈接地址不同的原因,實際上A函數已經被放到了0x0001,所以執行就會出錯。所以,當這兩個地址不同的時候,執行一段位置有關碼的時候就會發生不可預估的錯誤。
2、為什麼會出現鏈接地址跟運行地址不同的情況?
答:當一塊晶元啟動的時候,依靠內部的SRAM,可以運行一小段代碼,而因為DDR還沒初始化,註定了開始的運行地址是在內部SRAM中的。當我們需要運行一個操作系統,那麼點的記憶體怎麼夠運行呢?所以這時候就需要初始化DDR才可,而因為我們知道這代碼將來都是在DDR上面運行的,所以鏈接腳本指定的鏈接地址肯定是DDR上面的地址,所以這就出現了鏈接地址跟運行地址不同的情況了。
3、什麼是重定位?
答:由於出現1這樣的問題,就需要使用重定位這種方式解決上面的問題了。那什麼是重定位呢?重定位就是在鏈接地址跟運行地址不同的情況下,執行一段位置無關碼,這段位置無關碼的作用就是將原來的那份代碼全部複製到鏈接地址那裡去,然後自己再長跳轉到新的那份代碼的剛剛執行的那個位置。這樣就實現了鏈接地址跟運行地址一致的情況了。
4、為什麼需要重定位?
答:就是鏈接地址跟運行地址不同,在這個情況下我們可以有兩種方案:
①全部使用位置無關碼。
②進行重定位讓這兩個地址相同。
我們知道,如果是一個小代碼,使用①時可以的,但是一個大的代碼文件很難保證全部都使用位置無關碼的,這也是不現實的,所以必須使用重定位解決這個問題。