常用的一些調用約定


調用約定

調用約定

調用約定 參數壓棧 平衡堆棧
_cdecl 從右至左 調用者清理
_stdcall 從右至左 自身清理
_fastcall ecx/edx傳送兩個剩下的從右至左 自身清理
_thiscall 參數從右向左入棧 由ecx傳遞this指針,自身清理
_x64call 參數從右向左, RCX, RDX, R8, R9 自身清理

cdecl

cdecl(C declaration,即C聲明)是源起C語言的一種調用約定,也是C語言的事實上的標准。

  1. 函數實參在線程棧上按照從右至左的順序依次壓棧。
  2. 函數結果保存在寄存器EAX/AX/AL中
  3. 浮點型結果存放在寄存器ST0中
  4. 編譯后的函數名前綴以一個下划線字符
  5. 調用者負責從線程棧中彈出實參(即清棧)
  6. 8比特或者16比特長的整形實參提升為32比特長。
  7. 受到函數調用影響的寄存器(volatile registers):EAX, ECX, EDX, ST0 - ST7, ES, GS
  8. 不受函數調用影響的寄存器: EBX, EBP, ESP, EDI, ESI, CS, DS
  9. RET指令從函數被調用者返回到調用者(實質上是讀取寄存器EBP所指的線程棧之處保存的函數返回地址並加載到IP寄存器)

thiscall

在調用C++非靜態成員函數時使用此約定。基於所使用的編譯器和函數是否使用可變參數,有兩個主流版本的thiscall。 對於GCC編譯器,thiscall幾乎與cdecl等同:調用者清理堆棧,參數從右到左傳遞。差別在於this指針,thiscall會在最后把this指針推入棧中,即相當於在函數原型中是隱式的左數第一個參數。

微軟Visual C++編譯器中,this指針通過ECX寄存器傳遞,其余同cdecl約定。當函數使用可變參數,此時調用者負責清理堆棧(參考cdecl)。thiscall約定只在微軟Visual C++ 2005及其之后的版本被顯式指定。其他編譯器中,thiscall並不是一個關鍵字(反匯編器如IDA使用__thiscall)。

微軟x86-64調用約定

在Windows x64環境下編譯代碼時,只有一種調用約定,也就是說32位下的各種約定在64位下統一成一種了。

微軟x64調用約定使用RCX, RDX, R8, R9四個寄存器用於存儲函數調用時的4個參數(從左到右),使用XMM0, XMM1, XMM2, XMM3來傳遞浮點變量。其他的參數直接入棧(從右至左)。整型返回值放置在RAX中,浮點返回值在XMM0中。少於64位的參數並沒有做零擴展,此時高位充斥着垃圾。

在微軟x64調用約定中,調用者的一個職責是在調用函數之前(無論實際的傳參使用多大空間),在棧上的函數返回地址之上(靠近棧頂)分配一個32字節的“影子空間”;並且在調用結束后從棧上彈掉此空間。影子空間是用來給RCX, RDX, R8和R9提供保存值的空間,即使是對於少於四個參數的函數也要分配這32個字節。

例如, 一個函數擁有5個整型參數,第一個到第四個放在寄存器中,第五個就被推到影子空間之外的棧頂。當函數被調用,此棧用來組成返回值----影子空間32位+第五個參數。

在x86-64體系下,Visual Studio 2008在XMM6和XMM7中(同樣的有XMM8到XMM15)存儲浮點數。結果對於用戶寫的匯編語言例程,必須保存XMM6和XMM7(x86不用保存這兩個寄存器),這也就是說,在x86和x86-64之間移植匯編例程時,需要注意在函數調用之前/之后,要保存/恢復XMM6和XMM7。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM