天天看點

bl 和 ldr跳轉程式的差別

首先說明

BL main 為相對跳轉指令,與位置無關代碼。

LDR PC,=main 為絕對跳轉指令,與位置有關代碼。

可能看到這的人都有疑問,如下圖。連結位址為0x50000000。

bl 和 ldr跳轉程式的差別

兩段代碼main函數位置如下圖:

bl 和 ldr跳轉程式的差別

左右圖的第11行 左邊是 bl main的反彙編為 “ bl 50000298 ”,右邊是 ldr pc,=main的反彙編為 " ldr pc,[pc, #4] "

乍一看第一個 bl 50000298 不是直接跳轉到 50000298麼,那不就是絕對跳轉? ,第二個使用 ldr pc,[pc, #4],使用的時pc偏移量不是相對跳轉麼?

那你就中記了。

arm-linux-objdump的反彙編太貼心了。

左邊圖:

              反彙編軟體在反彙編的時候把你的bl mian這條語句中的main的位址幫你計算了出來。但是,,它并不是按照你的實際運作位址計算的而是按照你的連結位址來的,

是以就出現了bl 50000298;正如左邊圖示的main函數位置。

右邊圖:

            ldr pc, =main這條指令為僞指令,編譯的時候會将main的連結位址存入一個位址。再将 ldr pc, =main轉化為 ldr pc, [ pc, offset ]這樣一個指令。是以上面的反彙編出來的 ldr pc, =main 就變成了 ldr pc. [ pc, #4 ],這句代碼相當于  pc = *(pc+4); 由于ARM使用了流水線的原因,是以在執行 ldr pc. [ pc, #4 ]的時候 pc 不在這句代碼這裡了,而是跑到了 pc+8的地方,而 pc = *(pc + 4) = 5000029c 注意!!!!!!!! 這裡的   5000029c  是存在代碼段中的一個常量,并不是計算出來的,不會随程式的位置而改變,是以無論代碼和pc怎麼變 *(pc+4) 的值時不會變的。

到這還是不明白為什麼bl main是相對跳轉 ,ldr pc, =main是絕對跳轉,反而是兩個指令都是絕對跳轉了。

上面說了,反彙編軟體在反彙編BL main時幫我們把main的位址算出來了,,那我們看看它時怎麼算的,,,,,,費了好大力氣終于找到了BL跳轉指令的計算方法(大神見笑了),看圖:(該圖取至 《ARM體系結構與程式設計》--- 杜春雷 Page 59)

bl 和 ldr跳轉程式的差別

此時我們來模拟一下反彙編軟體的計算過程:(為友善了解我們假設程式在 50000000處執行)

           看一下左圖 50000010 處的機器碼為 eb0000a0 轉化成二進制就是 1110 1011 0000 0000 0000 0000 1010 0000

最高4位時條件碼 1110 就是無條件執行 (《ARM體系結構與程式設計》 Page 23)。

接着的4位 1011 是BL指令的指令碼。

後面的24位0000 0000 0000 0000 1010 0000 即為位址碼

按照其計算方式:

     1、将指令中24位帶符号的補碼立即數擴充為32位(擴充其符号位)

            原數變成  0000 0000 0000 0000 0000 0000 1010 0000

     2、将此數左移兩位

            變成    0000 0000 0000 0000 0000 0010 1000 0000 =  0x280

     3、将得到的值加到PC寄存器中得到目标位址

           由于ARM流水線原因 此時的 pc = 0x50000010+8 = 0x50000018

           pc = pc + 0x280 = 0x50000298與左邊圖中的mian的位址相等。程式就跳轉到了mian

在算的過程中我們使用的始終是PC的值,假設程式在 0 位址處執行,那麼計算方法一樣,pc 的值變了計算出來的結果也随之改變。是以 BL 的跳轉時與位置無關的

繼續閱讀