目錄
-
- 代碼
- 反彙編
-
- 對比
- 解析
- 總結
- dis和bin對比
代碼
首先回顧代碼
/*
*點亮LED:GPF4
*/
.text //表明它是代碼段
.global _start
_start:
/*配置GPF4為輸出引腳
*把0x100寫到位址0x56000050上,熄滅led
*/
ldr r1, =0x56000050 /*将這個位址存放到r1中*/
ldr r0, =0x100 /*或者使用 mov r0, #0x100 将0x100放入r0 */
str r0, [r1] /*将r0的值寫入到r1的位址中*/
/*設定GPF4輸出高電平
*把0x00寫到位址0x56000054上,點亮led
*/
ldr r1, =0x56000054 /*将這個位址存放到r1中*/
ldr r0, =0 /*或者使用 mov r0, #0x100 将0放入r0 */
str r0, [r1] /*将r0的值寫入到r1的位址中*/
halt: /*假設這個程式隻有十幾個位元組*/
b halt /*這十幾個位元組後的内容是不确定的,是以要讓他在這裡死循環*/
我們使用的ldr是僞指令,将位址存放在r1和r0中
僞指令,就是假的arm指令
它對應哪些真正的arm指令呢
反彙編
要想知道這個僞指令對應的真正的arm指令
我們就需要将elf檔案反彙編
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL2gDO3EDMykTMyIjMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
arm-linux-objdump -D led.elf > led.dis
輸入指令反彙編
将生成的dis檔案傳到windows,并使用notepad打開
對比
左側是我們使用的僞指令
可以看到真實的arm指令,是将這個位址放在記憶體中,使用pc讀取記憶體中1c和20的位址給r1
第二條指令直接使用mov,将位址存放在r0當中
解析
2440中有CPU,CPU中有r0到r15,16個寄存器。這裡是如何使用PC值來表示寄存器呢
-
pc——Program Counter(程式計數器)
當你把一個位址寫道R15也就是程式計數器時,程式就跳到那個位址中去
位址為目前指令的位址+8
-
lr——Link Register(傳回位址)
使用函數調用的時候,執行完畢要跳回原來的地方。R14/lr就是用來儲存原來的位址
- st——Stack Pointer(棧指針)
PC是什麼?
目前指令的位址使0,PC的位址是目前指令加8
因為ARM系統裡面,為了使執行效率更加高,CPU是以流水線的方式執行的
- 流水線:目前執行位址A的指令;已經在對位址A+4的指令進行譯碼;已經在讀取位址A+8(PC)的指令。
對于上面的圖
r1的值,等于[pc+20]這個位址的值,等于[8+20],28對應16進制就是0x1c
即,r1的值,就是0x1c位址中存放的值,就是0x5600,0050
第三條指令,将0x100寫入r1對應的記憶體,就是把0x100寫入0x5600,0050
第四條指令,r1等于[pc+12]=[0xc+8+12]=[32]=[0x20]
即,去0x20這個位址讀取值,存放到r1裡面,就是0x5600,0054
總結
在程式裡面,寄存器和記憶體沒有本質的差别。CPU都把它們當作記憶體來使用
隻是這些記憶體比較特殊,配置他們能控制一些引腳
dis和bin對比
dis是反彙編檔案
我們知道,bin檔案中都是二進制的機器碼,那麼我們來對比以下dis的彙編碼和bin中的機器碼
可以看到是完全一緻的
反彙編dis檔案中的彙編碼的源頭們就是我們編寫的代碼,那些僞指令和彙編碼
步驟如下
- 編譯器将僞指令轉化為真正的彙編碼,對于真正的彙編碼保持不變
- 轉換完成後,将所有的彙編碼轉換為機器碼,然後存為bin檔案。這些bin檔案就可以直接燒寫到單闆上了。