首先看兩行匯編代碼:
1: adr r0, _start
2: ldr r1, =_start
同樣是加載一個標號的地址值,adr和ldr有什麼區別呢?注意這裡的ldr不是命令ldr,而是偽指令ldr,若想區分它們請參看我的一篇博文《adr adrl ldr mov總結整理》。
要區分它們,就需要引入4個概念:
1、運行時地址起始位置:它芯片公司指定的一開始運行代碼的位置。這個位置和芯片本身有關,不可改動。對於2440來說一般就是片內SRAM的首地址0x0;對於210來說就是片內SRAM中的地址0xD0020010。
2、鏈接地址起始位置:它是由程序員指定的,或者說是有鏈接腳本設定。是可以變動的。但是這個位置在程序鏈接之後,就會確定下來。
3、運行時地址:就在從運行時地址起始位置(包括起始位置)往後排都是運行時地址。
4、鏈接地址:就是從鏈接地址起始位置(包括起始位置)往後排都是鏈接地址。
說明了以上4點內容之後,我需要鋪墊一些前提內容,adr r0, _start ; ldr r1, =_start
這兩句代碼是從朱老師的一個實驗程序裡直接截取出來,這實驗的目的是演示重定位。之後這段代碼我會貼到文章的最後。因為開發板是210的板子所以運行時地址是從0xd0020010開始的,鏈接地址設置為0xd0024000開始的。
整個程序編譯之後,在進行反編譯,我們查找adr r0, _start ; ldr r1, =_start 對應的反匯編內容:
1、adr r0, _start 對應的是: d002401c: e24f0024 sub r0, pc, #36 ; 0x24 2、ldr r1, =_start對應的是: d0024020: e59f1048 ldr r1, [pc, #72] ; d0024070 <run_on_dram+0x10>
同樣是加載_start的地址,反匯編之後卻是截然不同的命令。首先我們需要會看反匯編,最左邊的是鏈接地址,第二個是機器碼,第三個是反匯編得到的內容,最右邊分號之後的是反匯編編譯器額外幫我們注釋了一些內容方便我們閱讀。
我們發現反匯編之後,有一個地方很不同,就是pc指針。ldr r1, =_start對於的反匯編pc指針被放到的了[]裡面,而另一條反匯編沒有。我們知道對於匯編而言,放到[]裡面代表是取得寄存器的值並且將寄存器的值當作地址,來訪問地址中存儲的值。
而對於pc而言,當你直接讀取pc的值時訪問的是運行時地址,而當你讀取[pc]的值時訪問的是鏈接地址。
反觀adr r0, _start 和ldr r1, =_start它們都是偽指令,意思也分別是讀取運行時地址和讀取鏈接地址。和反匯編意義吻合。
我們現在來驗證,我們前面分析的是否正確。首先_start作為程序的最開始,所以_start如果對應運行時地址,那麼讀取的_start的值應該是運行時地址起始位置及0xd0020010。
觀察反匯編及對應的匯編
1、adr r0, _start d002401c: e24f0024 sub r0, pc, #36 ; 0x24
由於此時該句代碼的鏈接地址是d002401c鏈接地址的起始位置設定的是0xd0024000,偏移量是0x1c,根據這個便宜量可以算出該句代碼的運行時地址為0xd0020010 +0x1c = d002002C,前面提到pc的值對應的就是運行時地址所以pc = d002002C。
d002002C - (36 十進制)+ 8 (流水線)= D002 0010 ;正好得到了_start的運行時地址完全沒錯。
再看鏈接地址是否算錯,首先_start作為程序的最開始,所以_start如果對應鏈接地址,那麼讀取的_start的值應該是鏈接地址起始位置及之前設定的0xd0024000。
2、ldr r1, =_start d0024020: e59f1048 ldr r1, [pc, #72] ; d0024070 <run_on_dram+0x10>
根據偏移量,這句的運行時地址是d0020030,如果說是運行時地址 + 偏移量(72十進制),得到的是D002 0078,再加8(流水線)等於D002 0080,顯然不對。
明顯這裡的[pc]的值得到的是當前語句對應的鏈接地址,d0024020 + 偏移量(72十進制)+ 8 才等於D002 4070(這個值也正好是注釋裡的值)大家是不是奇怪,為啥值不是0xd0024000?是不是算錯了?其實不是,你到D002 4070這個鏈接地址看看就會發現這裡存放的值正好就是D002 4070。
代碼如下:d0024070: d0024000 andle r4, r2, r0
這裡符合ldr r1, [pc, #72]這句指令的本意,他訪問的就是這個值代表的地址中的值。(這種跳轉的方法其實就是為了應對非法立即數,導致在一個機器碼裡放不下命令和數據的情況)
朱老師代碼如下: