x64位匯編學習(二)、調用約定與棧幀


一、32位下的調用約定

1、__cdecl

 
0
 
0
外平棧,從右至左入棧

2、__stdcall

__stdcall是windows API的默認調用約定
0
內平棧,從右至左入棧

3、__fastcall

0
 
0
內平棧,從右至左入棧,但前兩個參數被分別放在了ecx,edx寄存器中
 

二、64位下的調用約定

64位下只有一種調用約定,即__fastcall
但64位下的__fastcall與32位下的__fastcall有不小差異
64位下的__fastcall是外平棧,從右至左入棧

1、64位下前四個參數分別保存在rcx,rdx,r8,r9寄存器中

2、就算是寄存器傳參,64位下在調用函數前一樣分配棧空間(存疑)

3、對於不定長參數,調用前至少分配四個參數的棧空間

我們構造不定長函數test:
0
 
0
我只傳遞了一個參數,但它需要保存rcx,rdx,r8,r9四個寄存器,同理,如果我們在其內部調用printf函數,需要在調用前至少分配4個參數的棧空間
0
 
0

4、push,pop指令僅僅保存非易變寄存器

易變寄存器包括:rax,rcx,rdx,r8,r9,r10,r11
用IDA64隨便打開一個64位文件
alt + t搜索push ,可以發現,幾乎所有的push指令都屬於非易變寄存器,且根本沒有push一個立即數的情況
 
0

5、64位下,通常使用rsp尋址(一次性分配局部變量和參數空間)

32位下,我們經常看到[esp + xx]或[ebp + xx]的字樣
但在64位下,使用的基本都是rsp
所以,這也導致64位下一次性分配局部變量和參數空間
64位下的fastcall是外平棧,但我們常常見不到外平棧的身影,這就是因為64位一次性分配局部變量和參數空間
這點,和32位大不一樣
 

6、64位下的call的棧地址一般都是0x10對齊

 

7、棧幀

程序進入函數的時候會push rbp,我們把兩個push rbp之間的棧稱為棧幀
或者在棧上兩個保存函數返回地址的區段叫做棧幀
0
0
這兩個r之間就是棧幀
其棧幀分析如下
0
rsp + 28的位置只是為了對齊
本來我們在IDA上看到的反匯編是這樣的: rsp + 0x38h + var_xx 之類的
0
0
所以說IDA喜歡以0x38h的那個ret上做基准引用

8、葉函數

葉函數的概念
像下面的main函數就算葉函數
0
非葉函數至少分配4個參數的棧空間
上面的main函數也只是分配了0x10個字節的空間(0x10是為了滿足對齊)
0
 


免責聲明!

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



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