热门问题
时间线
聊天
视角
呼叫約定
来自维基百科,自由的百科全书
Remove ads
在電腦科學中,呼叫約定(calling convention)是一種定義子過程從呼叫處接受參數以及返回結果的方法的約定。不同呼叫約定的區別在於:
- 參數和返回值放置的位置(在暫存器中;在呼叫棧中;兩者混合)
- 參數傳遞的順序(或者單個參數不同部分的順序)
- 呼叫前設置和呼叫後清理的工作,在呼叫者和被呼叫者之間如何分配
- 被呼叫者可以直接使用哪一個暫存器有時也包括在內。(否則的話被當成ABI的細節)
- 哪一個暫存器被當作volatile的或者非volatile的,並且如果是volatile的,不需要被呼叫者恢復
架構舉例
32-位版本的x86架構使用了很多不同的呼叫約定。由於有着少量的架構暫存器,以及在歷史上聚焦於簡單性和更小代碼大小,很多x86呼叫約定傳遞實際參數於堆疊之上。返回值(或到它的指標)被返回在一個暫存器中。一些約定對前幾個實際參數使用暫存器,這可以增進效能,特別是對於被頻繁呼叫的短小而簡單的葉次常式(就是不呼叫其他常式的常式)。
例子呼叫:
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
64-位版本的x86架構,叫做x86-64、x64、AMD64或Intel 64,有兩個公用的呼叫序列[1]。一個呼叫序列是Microsoft定義的x64呼叫約定,用於Windows;另一個呼叫序列規定於System V AMD64 ABI,用於類Unix系統,並在改動後用於OpenVMS。由於x86-64比32-位x86有更多的通用暫存器,兩個約定都傳遞一些實際參數於暫存器之中。
標準32-位ARM呼叫約定分配16個通用暫存器為:
- r15:程式計數器(依據指令集規定)。
- r14:連結暫存器。BL指令,用在次常式呼叫中,儲存返回地址於此暫存器。
- r13:堆疊暫存器。PUSH和POP指令在「Thumb」執行模態下只使用這個暫存器。
- r12:過程呼叫內部(Intra-Procedure-call)暫存(scratch)暫存器。
- r4 至 r11:局部變量。
- r0 至 r3:傳給次常式的實際參數值和從次常式返回的結果值。
如果返回值的類型對於放入r0至r3太大,或者其大小在編譯時間不能靜態的確定,那麼呼叫者必須在執行時間為這個值分配空間,並傳遞到這個空間的一個指標於r0,
次常式必須保持(preserve)r4至r11和棧指標的內容,這可以通過在函數前言中將其儲存至堆疊,接着使用它們為暫存空間,接着在函數結語中從堆疊復原它們。特別是,呼叫其他次常式的次常式,在呼叫這些其他次常式之前,「必須」將連結暫存器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
64-位ARM(AArch64)呼叫約定分配31個通用暫存器為[3]:
- x31 (SP):棧指標或零暫存器,依賴上下文。
- x30 (LR):過程連結暫存器,用於從次常式返回。
- 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
參見
參考文獻
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads