1. 程式人生 > >64位匯編第二講——64位匯編中局部變量使用及擡棧方法29171230

64位匯編第二講——64位匯編中局部變量使用及擡棧方法29171230

add 我們 根據 them cal 因此 處理 data 對象

一.純寫64位匯編時局部變量處理和參數寄存器保存位置 純寫64位匯編和用VS2013寫64位C代碼生成的匯編會有一些格式上的區別,VS2013寫64位C代碼生成的匯編中是沒用到棧基址寄存器rbp的,但是純寫匯編時只要申明了參數和使用了@LOCAL定義的局部變量,就會用到rbp。且看如下例子:1)用C寫64位程序空函數生成的匯編代碼,
;C代碼
void FunTest2()
{
}
;匯編代碼
000000013F753290 40 57                push        rdi  
000000013F753292 5F                   pop         rdi  
000000013F753293 C3                   ret  
2)在*.asm文件中寫一個空函數,並且生成可執行文件,然後在X64dbg中查看其匯編代碼如下, |
;無參無@LOCAL局部變量時的情形,不過會比較少,因為不多時候都會用到@LOCAL局部變量
MyAdd proc
  ret
MyAdd endp
 
000000013F231000 | C3                   | ret                                     |
    
;申明了參數的情形    
MyAdd proc n1:DWORD, n2:DWORD, n3:DWORD, n4:DWORD, n5:DWORD, n6:DWORD
  ret
MyAdd endp    
 
000000013F5A1000 
| 55 | push rbp | 000000013F5A1001 | 48 8B EC | mov rbp,rsp | 000000013F5A1004 | C9 | leave | 000000013F5A1005 | C3 | ret | ;用到@LOCAL定義的局部變量的情形 MyAdd proc ;n1:DWORD, n2:DWORD, n3:DWORD, n4:DWORD, n5:DWORD, n6:DWORD LOCAL @n : Qword ret MyAdd endp 000000013FBB1000
| 55 | push rbp | 000000013FBB1001 | 48 8B EC | mov rbp,rsp | 000000013FBB1004 | 48 83 C4 F8 | add rsp,FFFFFFFFFFFFFFF8 | 000000013FBB1008 | C9 | leave | 000000013FBB1009 | C3 | ret

在寫匯編代碼時,如果用到基址寄存器,則不用每次都計算擡棧的個數,能大大的方便程序員寫代碼。在上一次課中講到64位匯編會騰出至少0x28的空間給調用的函數保存參數寄存器,那麽騰出來後該如何存放,參數寄存器的值存放擡0x28字節棧的地址處,因為此時用棧基址寄存器很好訪問,如下:

技術分享圖片 其實在64位程序的設計上,如果有第五個或以上的參數,則是要通過棧傳參的,同一個函數中所有的call中,在第一個call之前將所有的參數所需棧大小一起擡了,這能減少函數參數的出棧和入棧,從而提高效率。當然,試想我們能不能在call之間還擡棧呢?是不能的,因為只要一擡棧,rsp的值必然會改變,那麽call的函數中要保存參數寄存器通過rsp+8尋址就會有偏差了。其實咋一看這樣設計會給64位匯編程序開發造成很大的麻煩,因為每添加一個有第五個參數的call時,就要重新修改擡棧的數量,不過細細想來,我們可以用宏來開發,這樣就可以直接改宏就可以了,並且在每個call前註釋好它單個擡的棧的大小,方便之後統計校對。 另外一個問題是64位匯編中程序中,該不該用LOCAL類型的局部變量的。用LOCAL類型的局部變量的好處是可以直接通過結構體對象點出成員,使用很方便,這也是64位匯編中唯一可以用作結構體對象點成員的方法,在32位匯編中還可用ASSUME,但64位匯編中ASSUME失效。另外,LOCAL類型的局部變量還是自動擡棧和平棧的,其中使用到了rbp,但也因此擡了8字節的棧,改變了rsp,所以此時只能由rbp+10h來替代rsp+8來保存參數寄存器的值。那麽除了LOCAL類型的局部變量,還可以用戶自己擡棧來充當局部變量,這樣做相對於LOCAL類型的局部變量自然麻煩很多,因為老是要算esp的值和靜態局部變量總的自己大小,當然也不是不可能,用宏的話會稍微方便一些。 技術分享圖片 二. 64位匯編和32位匯編中數據類型的區別 64位匯編中地址是64位即8字節的,以前32位匯編中使用的結構體中對應到64位匯編中,個數和代表的含義都不邊,只是有的成員的字節數會變化,如涉及到地址的都會由四字節變成八字節,64位匯編中現成可使用的*.inc文件比較少,如果非要用,只能自己寫,但可以參考32位匯編中的結構體和宏,宏不需要改,直接拷貝就好,但結構體可以根據VS2013中64位匯編中結構體進行一些類型上的更改,主要是DWORD改QWORD。另外,64位匯編中函數聲明方式為extern 函數名:proc,如extern UpdateWindow:proc,包的頭文件方式同32位匯編。定義參數個數多余四個的函數時,同32位匯編中定義和申明,頭四個參數,在一開始就賦予rcx、rdx、r8、r9的值。

64位匯編第二講——64位匯編中局部變量使用及擡棧方法29171230