最簡函數

指令清單 C/C++ 代碼函數


int f()
{
    return 123;
}

1. x86

在開啓優化功能以後,GCC編譯器產生的彙編指令,以下所示
Optimizing GCC/MSVC(彙編輸出)優化

mov eax. 123
ret

MSVC編譯的程序和上述指令徹底一致
這個函數僅由兩條指令構成:第一條指令把數值123存放在EAX寄存器裏;根據函數調用約定,後面一條指令會把EAX的指看成返回值傳遞給調用者函數,而調用者函數(caller)會從EAX寄存器裏取值,把它看成返回結果。code

2. ARM

Optimizing Keil 6/2013(ARM模式)編譯器

PROC
    MOV  r0, #0x7b ;123
    BX     lr
    ENDP

ARM程序使用R0寄存器傳遞函數返回值,因此指令把數值123賦值給R0.
ARM程序使用LR寄存器(Link Register)存儲函數結束以後的返回地址(RA/Return Address).x86程序使用「棧」結構存儲上述返回地址。可見, BX lr指令做用是跳轉到返回地址,即返回到調用者函數,而後繼續執行調用體caller的後續指令。編譯

x86和ARM指令集的MOV指令確實和對應單詞「move」沒有什麼瓜葛。它的做用是複製copy,而非移動move。

3. MIPS

在MIPS指令集裏,寄存器有兩種命名方式。一種是以數字命名($0~$31),另外一種則是以僞名稱(pseudoname)命名($V0~VA0,依次類推)。在GCC編譯器生成的彙編指令中,寄存器都採用數字方式命名。
Optimizing GCC 4.45(彙編輸出)class

j  $31
li $2, 123   #0x7b

然而IDA會顯示寄存器的僞名稱。程序

Optimizing GCC 4.45 (IDA)im

jr  $ra
li $v0, 0x7B

根據僞名稱和寄存器數字編號的關係可知,存儲函數返回值的寄存器都是$2即($V0).此處LI指令是英文詞組「Load Immediate(加載當即數)」的縮寫。
其中,j和jr指令都屬跳轉指令,它們把執行流遞交給調用者函數,跳轉到$31即$RA寄存器中的地址。這個寄存器至關於ARM平臺的LR寄存器。
此外,爲何複製指令LI和轉移指令J/JR的位置反過來了?這屬於RISC精簡指令集的特性之一 --- 分支(轉移)延遲槽(Branch delay slot)的現象。簡單地說,無論分支(轉移)發生與否,位於分支指令的一條指令(在延遲槽裏的指令),老是被先於分支指令提交。這是RISC精簡指令集的一種特例。咱們沒必要在此處深究。總之,轉移指令後面的這條複製指令。其實是在轉移指令以前運行的。call

相關文章
相關標籤/搜索