裸函數及調用約定


裸函數

  在函數名前面加上  __deplspec(naked),此時,編譯器對該函數不會進行任何處理。

  想要在c語言里面寫匯編的語法,使用vc中輸入__asm

  對於一個裸函數而言,就是編譯器不會為這個函數生成代碼,想用匯編怎么寫就怎么寫,如果什么都不寫,一定會報錯,因為沒有生成ret。

  

 1 #include<stdio.h>
 2 void __deplspec(naked) Function()
 3 {
 4     __asm
 5         {
 6             //保留棧底
 7             push ebp    ;此時 esp=esp+4
 8             //提升棧底
 9             mov ebp,esp    ;此時 ebp=esp
10             sub esp,0x40    ;此處0x40即為緩沖區大小,可寫任意數值
11             
12             //保存現場
13             push ebx
14             push edi
15             push esi
16             
17             //往緩沖區中寫入數據
18             mov eax,0xCCCCCCCC
19             ;0xCCCC在gb2312中是燙字,寫C語言的時候出現燙燙燙就是這個原因,屯屯屯是0xCDCD,是堆的問題
20             mov ecx,0x10    ;此處的0x10是0x40除以4得到的
21             lea edi,dword ptr ds:[ebp-0x40]
22             rep stosd
23 
24             //實現函數功能的地方
25             
26             //恢復現場
27             pop esi
28             pop edi
29             pop ebx
30             //降低棧底
31             mov esp,ebp    ;降低esp
32             pop ebp    ;降低ebp
33             ret 
34         }
35 
36 }
37 
38 void main()
39 {
40     Function();
41 }     

在上面的例子中,我沒有傳入參數,假如傳遞參數,一般是在函數調用前push入堆棧,具體再后面會提到。

實現兩個數之和的代碼:

 1 #include<stdio.h>
 2 void __deplspec(naked) Add(int x,int y)
 3 {
 4     __asm
 5         {
 6             //保留棧底
 7             push ebp    ;此時 esp=esp+4
 8             //提升棧底
 9             mov ebp,esp    ;此時 ebp=esp
10             sub esp,0x40    ;此處0x40即為緩沖區大小,可寫任意數值
11             
12             //保存現場
13             push ebx
14             push edi
15             push esi
16             
17             //往緩沖區中寫入數據
18             mov eax,0xCCCCCCCC
19             ;0xCCCC在gb2312中是燙字,寫C語言的時候出現燙燙燙就是這個原因,屯屯屯是0xCDCD,是堆的問題
20             mov ecx,0x10    ;此處的0x10是0x40除以4得到的
21             lea edi,dword ptr ds:[ebp-0x40]
22             rep stosd
23             //實現兩個數之和的功能
24             mov eax,dword ptr ds:[ebp+0x8]
25             add eax,dword ptr ds:[ebp+0xC]
26             
27             
28             //恢復現場
29             pop esi
30             pop edi
31             pop ebx
32             //降低棧底
33             mov esp,ebp    ;降低esp
34             pop ebp    ;降低ebp
35             ret 8
36         }
37 
38 }
39 
40 void main()
41 {
42     add(2,3);
43 }     

假如存在局部變量,局部變量的存儲地方是在緩沖區中。例如,

實現參數求和之后在加上一個常數z的代碼:

 1 #include<stdio.h>
 2 void __deplspec(naked) Add(int x,int y)
 3 {
 4     __asm
 5         {
 6             //保留棧底
 7             push ebp    ;此時 esp=esp+4
 8             //提升棧底
 9             mov ebp,esp    ;此時 ebp=esp
10             sub esp,0x40    ;此處0x40即為緩沖區大小,可寫任意數值
11             
12             //保存現場
13             push ebx
14             push edi
15             push esi
16             
17             //往緩沖區中寫入數據
18             mov eax,0xCCCCCCCC
19             ;0xCCCC在gb2312中是燙字,寫C語言的時候出現燙燙燙就是這個原因,屯屯屯是0xCDCD,是堆的問題
20             mov ecx,0x10    ;此處的0x10是0x40除以4得到的
21             lea edi,dword ptr ds:[ebp-0x40]
22             rep stosd
23             
24             //實現的功能
25             mov dword ptr ds:[ebp-0x4],1    ;ebp-0x4處存放局部變量z,z=1
26             
27             mov eax,dword ptr ds:[ebp+0x8]
28             add eax,dword ptr ds:[ebp+0xC]
29             add eax,dword ptr ds:[ebp+0x10]
30             ;參數之和部分
31             
32             add eax,dword ptr ds:[ebp-0x4]    ;局部變量求和的部分
33             
34             //恢復現場
35             pop esi
36             pop edi
37             pop ebx
38             //降低棧底
39             mov esp,ebp    ;降低esp
40             pop ebp    ;降低ebp
41             ret 0xC
42         }
43 
44 }
45 
46 void main()
47 {
48     add(2,3,4);
49 }     

根據代碼可以得到,局部變量存放在ebp-0x4開始往低地址,參數是存放在ebp+0x8開始

 

 

調用約定

外平棧是指在函數外面平衡堆棧

內平棧是指在函數內部平衡堆棧

例如上面的例子中最后ret 0xC,就是內平棧,因為是在函數內部

外平棧一般是這樣

call   myfunction
add esp,xxxxx
;且ret后面無數字

call myfunction
call function_pinghengduizhan

 


免責聲明!

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



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