热门问题
时间线
聊天
视角

呼叫約定

来自维基百科,自由的百科全书

Remove ads

電腦科學中,呼叫約定(calling convention)是一種定義子過程從呼叫處接受參數以及返回結果的方法的約定。不同呼叫約定的區別在於:

  • 參數和返回值放置的位置(在暫存器中;在呼叫棧中;兩者混合)
  • 參數傳遞的順序(或者單個參數不同部分的順序)
  • 呼叫前設置和呼叫後清理的工作,在呼叫者和被呼叫者之間如何分配
  • 被呼叫者可以直接使用哪一個暫存器有時也包括在內。(否則的話被當成ABI的細節)
  • 哪一個暫存器被當作volatile的或者非volatile的,並且如果是volatile的,不需要被呼叫者恢復

架構舉例

x86 (32-位)

32-位版本的x86架構使用了很多不同的呼叫約定。由於有着少量的架構暫存器,以及在歷史上聚焦於簡單性和更小代碼大小,很多x86呼叫約定傳遞實際參數於堆疊之上。返回值(或到它的指標)被返回在一個暫存器中。一些約定對前幾個實際參數使用暫存器,這可以增進效能,特別是對於被頻繁呼叫的短小而簡單的葉次常式英語leaf routine(就是不呼叫其他常式的常式)。

例子呼叫:

  push EAX            ; 传递一些寄存器结果
  push dword [EBP+20] ; 传递一些内存变量(FASM/TASM语法)
  push 3              ; 传递一些常量
  call calc           ; 返回的结果将在EAX中

典型的被呼叫者結構如下,其中某些或全部(ret除外)指令在簡單過程中總是可以被最佳化掉的:

calc:
  push EBP            ; 保存旧的帧指针
  mov  EBP,ESP        ; 得到新的帧指针
  sub  ESP,localsize  ; 为局部变量预留空间
  .
  .                   ; 进行计算,留下结果于EAX
  .
  mov  ESP,EBP        ; 释放局部变量的空间
  pop  EBP            ; 复原旧的帧指针
  ret  paramsize      ; 释放参数空间并返回

一些約定留下分配的參數空間,使用平常的ret而非ret imm16。在這種情況下,呼叫者可以於此例子中add esp,12,或者用其他方式處置對ESP的變更。

Remove ads

x86-64

64-位版本的x86架構,叫做x86-64、x64、AMD64或Intel 64,有兩個公用的呼叫序列[1]。一個呼叫序列是Microsoft定義的x64呼叫約定,用於Windows;另一個呼叫序列規定於System V AMD64 ABI,用於類Unix系統,並在改動後用於OpenVMS。由於x86-64比32-位x86有更多的通用暫存器,兩個約定都傳遞一些實際參數於暫存器之中。

ARM (A32)

標準32-位ARM呼叫約定分配16個通用暫存器為:

  • r15:程式計數器(依據指令集規定)。
  • r14:連結暫存器英語Link register。BL指令,用在次常式呼叫中,儲存返回地址於此暫存器。
  • r13:堆疊暫存器。PUSH和POP指令在「Thumb」執行模態下只使用這個暫存器。
  • r12:過程呼叫內部(Intra-Procedure-call)暫存(scratch)暫存器。
  • r4 至 r11:局部變量。
  • r0 至 r3:傳給次常式的實際參數值和從次常式返回的結果值。

如果返回值的類型對於放入r0至r3太大,或者其大小在編譯時間不能靜態的確定,那麼呼叫者必須在執行時間為這個值分配空間,並傳遞到這個空間的一個指標於r0,

次常式必須保持(preserve)r4至r11和棧指標的內容,這可以通過在函數前言英語Function prologue and epilogue中將其儲存至堆疊,接着使用它們為暫存空間,接着在函數結語英語Function prologue and epilogue中從堆疊復原它們。特別是,呼叫其他次常式的次常式,在呼叫這些其他次常式之前,「必須」將連結暫存器r14中的返回地址儲存到堆疊。但是在返回之時,這樣的次常式不需要將這個值返回到r14,它們只需要將這個值裝載進入程式計數器r15。

ARM呼叫約定強制使用完全降序的堆疊。此外,棧指標必須總是4-位元組對齊,並且在具有公開介面的函數呼叫上必須總是8-位元組對齊[2]

呼叫約定導致「典型」的ARM次常式會:

  • 在前言中,將r4至r11壓入到堆疊,並將在r14中的返回地址壓入堆疊,這可以通過單一的STM指令完成;
  • 複製任何要傳遞的實際參數(在r0至r3中)到局部暫存暫存器(r4至r11);
  • 分配其他局部變量到剩餘的局部暫存器(r4至r11);
  • 進行計算並按需要使用BL呼叫其他次常式,假定r0至r3、r12和r14會被保持;
  • 將結果放入r0;
  • 在結語中,將r4至r11從堆疊取出,並取出返回地址放入程式計數器r15,這可以通過單一的LDM指令完成。
Remove ads

ARM (A64)

64-位ARM(AArch64)呼叫約定分配31個通用暫存器為[3]

  • x31 (SP):棧指標零暫存器,依賴上下文。
  • x30 (LR):過程連結暫存器英語Link register,用於從次常式返回。
  • x29 (FP):框指標
  • x19 至 x28:被呼叫者儲存。
  • x18 (PR):平台暫存器。用於某些作業系統特定的特殊功能,或一個額外的呼叫者儲存暫存器。
  • x16 (IP0) 和 x17 (IP1):過程呼叫內部(Intra-Procedure-call)暫存(scratch)暫存器。
  • x9 至 x15:局部變量,呼叫者儲存。
  • x8 (XR):間接返回值地址。
  • x0 至 x7:傳遞給次常式的實際參數值和從次常式返回的結果值。

所有以x開始的暫存器都由一個對應的字首着w的32-位暫存器,比如32-位x0叫做w0。

類似的,32個浮點暫存器被分配為[4]

  • v0 至 v7:傳入的實際參數值和從次常式返回的結果值。
  • v8 至 v15:被呼叫者儲存,但只有底部64位元需要被保持。
  • v16 至 v31:局部變量,呼叫者儲存。
Remove ads

參見

參考文獻

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads