天天看點

x86/x64/arm32/arm64等平台上的調用約定

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之後)使用引用指派傳回