x86:常見的是cdecl、stdcall、thiscall、fastcall、vectorcall。
cdecl | stdcall | thiscall | fastcall | vectorcall(基于fastcall) | |
---|---|---|---|---|---|
主要用于 | 大多數c語言程式 | win32 | 沒有可變參數的C++成員函數 | 手動使用 | msvc需要傳SSE和AVX參數時手動使用 |
非易失寄存器 | ebx esi edi ebp x87cw(x87堆棧需清空) | ||||
obj符号名稱修飾(*表示函數名) | _* | _*@n(n是參數位元組數) | 按照C++名稱修飾 | @*@n(n是參數位元組數) | *@@n(n是參數位元組數) |
寄存器參數 | 無 | 無 | this指針使用ecx | 第一個整數ecx 第二個整數edx | 第一個整數ecx 第二個整數edx 浮點或SSE參數xmm0-5 AVX參數ymm0-5 |
棧參數 | 倒序壓棧 | 倒序壓棧 | 其它參數倒序壓棧 | 其它參數倒序壓棧 | 其它參數倒序壓棧 |
清棧 | 調用者add esp,n*4 | 無可變參數:被調用者ret n*4 有可變參數:調用者add esp,n*4 | 被調用者ret n*4 | 被調用者ret n*4 | 被調用者ret n*4 |
傳回值 | 整數edx:eax 浮點st0 | 整數edx:eax 浮點和SSE傳回值xmm0-3 AVX傳回值ymm0-3 | |||
特殊寄存器 | 幀指針ebp,函數開頭第一個壓入,并且立即mov ebp,esp | ||||
C語言結構體參數 | 補齊到4位元組的倍數壓棧 | 正常結構體和fastcall相同 在配置設定完其它參數的寄存器之後,SSE/AVX結構體如果能完整放入剩餘寄存器,則放入寄存器,否則複制到臨時區域傳指針(注意和fastcall正常結構體不同) | |||
C語言結構體傳回值 | 8位元組以内按照整數傳回,否則作為第一個參數(在this之後)使用指針指派傳回 | 正常結構體和fastcall相同 在配置設定完其它參數的寄存器之後,SSE/AVX結構體如果能完整放入剩餘寄存器,則放入寄存器,否則作為第一個參數(在this之後)使用指針指派傳回 | |||
有構造和析構函數的C++類 | 參數:複制到臨時區域傳引用 傳回值:作為第一個參數(在this之後)使用引用指派傳回 |
x64:常見的是ms_abi、sysv_abi、vectorcall。
ms_abi | sysv_abi | vectorcall(基于ms_abi) | |
---|---|---|---|
使用範圍 | win64和uefi | linux等其它作業系統 | msvc需要傳遞SSE和AVX參數時手動使用 |
obj符号名稱修飾(*表示函數名) | 無 | 無 | *@@n(n是參數位元組數) |
rsp對齊要求 | 所有調用其它函數的函數,除prolog和epilog外的地方rsp均需要16位元組對齊 | call之前rsp需要16位元組對齊(如果調用樹在同一個.c中,而且均沒有使用SSE或AVX,GCC會優化為call之前不對齊) | 和ms_abi相同 |
非易失寄存器 | rbx rbp rsp rsi rdi r12-r15 xmm6-15 x87cw(fpcsr) mxcsr[6:15](所有控制位) | rbx rbp rsp r12-r15 x87cw(fpcsr) mxcsr[6:15](所有控制位) | 和ms_abi相同 |
寄存器參數 | 參數1-4整數/浮點 rcx/xmm0 rdx/xmm1 r8/xmm2 r9/xmm3 | 前6個整數rdi rsi rdx rcx r8 r9 前8個浮點xmm0-7 若存在可變參數,使用了的浮點寄存器數量al | 參數1-4整數/浮點或SSE/AVX: rcx/xmm0/ymm0 rdx/xmm1/ymm1 r8/xmm2/ymm2 r9/xmm3/ymm3 參數5-6浮點或SSE/AVX: xmm4/ymm4 xmm5/ymm5 |
傳回值 | 整數rax 浮點xmm0 | 整數rax rdx 浮點xmm0 xmm1 long double用st0 st1 | 整數傳回值rax 浮點或SSE傳回值xmm0-3 AVX傳回值ymm0-3 |
棧參數 | [rsp+(0~3)*8]:前4個參數預留位置 [rsp+(4~(n-1))*8]:第5~n個參數 | 不能放進寄存器的參數倒序壓棧 | 正常參數和ms_abi相同 SSE/AVX參數:能放進寄存器的在棧上預留8位元組位置,不能放進寄存器的複制到臨時區域傳指針 |
棧上參數慣用指令 | sub rsp,n*8預留 mov [rsp+n*8],x寫入 add rsp,n*8清除 | 直接push x壓入 sub rsp,n*8進行非寫入性調整 變種:lea rsp,-8[rsp] add rsp,n*8清除 | 和ms_abi相同 |
rsp以下128位元組red zone | 無 | 有(可使用-mno-red-zone關閉) | 和ms_abi相同 |
特殊寄存器 | rbp用于幀指針,函數開頭第一個壓入,并且立即mov rbp,rsp(可選) | rbp用于幀指針,函數開頭第一個壓入,并且立即mov rbp,rsp(可選) r10用于靜态鍊指針 r15用于global offset pointer指針(可選) | 和ms_abi相同 |
C語言結構體參數 | 8位元組以内:按整數傳遞 超過8位元組:複制到臨時區域傳指針 | 32位元組純浮點數:若可整體放入,則放入浮點寄存器 16位元組純整數或整數/浮點混合:若可整體放入,則放入整數寄存器 否則補齊到8位元組的倍數壓棧 | 正常結構體和ms_abi相同 在配置設定完其它參數的寄存器之後,SSE/AVX結構體如果能完整放入剩餘寄存器,則放入寄存器,并在棧上預留8位元組位置,否則複制到臨時區域傳指針 |
C語言結構體傳回值 | 8位元組以内:按整數傳遞 超過8位元組:作為第一個參數(在this之後)使用指針指派傳回 | 使用寄存器規則與參數規則相同,若不滿足,作為第一個參數(在this之後)使用指針指派傳回 | 正常結構體和ms_abi相同 在配置設定完其它參數的寄存器之後,SSE/AVX結構體如果能完整放入剩餘寄存器,則放入寄存器,否則作為第一個參數(在this之後)使用指針指派傳回 |
有構造和析構函數的C++類 | 參數:複制到臨時區域傳引用 傳回值:作為第一個參數(在this之後)使用引用指派傳回 |
arm32/arm64:arm32常見的是eabi、eabihf,arm64隻有一種調用約定。
和x86/x64不同,arm32的不同調用約定不可互相調用,程式和它所依賴的庫隻能使用同一種調用約定。
arm32 eabi | arm32 eabihf | arm64 | |
---|---|---|---|
主要用于 | 單片機、沒有硬浮點的linux裝置 | windows、uefi、有硬浮點的linux裝置 | 所有arm64裝置 |
非易失寄存器 | r4-r11(fp) sp(r13) lr(r14) pc(r15) | r4-r11(fp) sp(r13) lr(r14) pc(r15) s16-s31/d8-d15/q4-q7 fpcsr[8-12,15-18,20-26](所有控制位) | x18-x28 fp(x29) lr(x30) v8-v15 fpcsr[8-12,15,22-26](所有控制位) |
sp對齊要求 | 始終對齊到4位元組 | 始終對齊到4位元組 | 始終對齊到16位元組(否則引用sp會産生異常) |
寄存器參數 | r0-r3 | 整數r0-r3 浮點s0-s15/d0-d7/q0-q4 可變參數不使用浮點寄存器 | 整數x0-x7 浮點v0-v7 可變參數不使用浮點寄存器 |
棧參數 | 倒序壓棧,調用者清棧,如果需8位元組對齊則對齊 | 倒序壓棧,調用者清棧,如果需16位元組對齊則對齊 | |
傳回值 | r0-r1 | 整數r0-r1 浮點s0-s3/d0-d1/q0 | 整數x0 浮點v0 |
特殊寄存器 | r9(sb/tr)平台寄存器 r11(fp)幀指針 r12(ip)過程調用間臨時寄存器 r13(sp)棧頂指針 r14(lr)連結寄存器(傳回位址) r15(pc)程式計數器 | x16-17(ip0-1)過程調用間臨時寄存器 x18平台寄存器 x29(fp)幀指針 x30(lr)連結寄存器(傳回位址) sp棧頂指針 | |
C結構體參數 | 盡可能放進整數寄存器,放不進去的部分壓棧 | 16位元組以内:作為整數傳遞 超過16位元組:複制到臨時區域傳指針 | |
C結構體傳回值 | 4位元組以内:作為整數傳回 超過4位元組:作為第一個參數(在this之後)使用指針指派傳回 | 16位元組以内:作為整數傳回 超過16位元組:作為第一個參數(在this之後)使用指針指派傳回 | |
有構造和析構函數的C++類 | 參數:複制到臨時區域傳引用 傳回值:作為第一個參數(在this之後)使用引用指派傳回 |