win32asm中的参数传递与堆栈

   在win32asm中主要包含了两种参数传递方式:
1 stdcall
 这种是windows api中使用的标准的参数传递(除了wsprintf这个函数),使用从右到左的传递顺序,堆栈清空由被调用函数完成
1  ; Example of calling a stdcall function:
2  ; MessageBeep prototype:
3  ; int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
4
5      push    MB_OK             ; uType
6      push    offset szCaption  ; lpCaption
7      push    offset szText     ; lpText
8      push    [hWnd]            ; hWnd
9      call    MessageBoxA

2 c
这种也是采用了从右到左的传递顺序,但是堆栈的清空由调用者清空
1  ; Example of calling a C function:
2  ; wsprintf prototype: int cdecl wsprintf(LPTSTR  lpOut, LPCTSTR  lpFmt, );
3
4      push    345h               ; vararg 2
5      push    1                  ; vararg 1
6      push    offset szFormat    ; lpFmt
7      push    offset szOutput    ; lpOut
8      call    wsprintf
9      add     esp, 16            ; clean stack
这里的第9行,可以看到把esp寄存器值+16了,因为该函数使用了4个参数,每个参数占了 4个字节,所以在清空堆栈时要把esp恢复到初始值 就要加16。为什么这样那?我自己的估计是这个函数参数不定  ,所以要做到清空堆栈恢复esp的初始值调用者是最清楚的,就交给他恢复,而其他的win api由于参数个数固定 ,被调用函数自身可以知道使用的堆栈的大小,就可以自己清空 。
 
上次没写完,今天继续
C SysCall StdCall Basic Fortran Pascal
参数从左到右      
参数从右到左      
调用者清除堆栈          
允许使用:VARARG      

这个表中可以看到常用的参数调用的特性,syscall和stdcall中可以用VARARG,但是用的时候必须调用者清除堆栈,也就是相当于C调用了。

在使用堆栈时主要使用的寄存器就是EBP和ESP两个了。一般ESP存放栈顶指针,这个自不用说。
那EBP呢?
其实EBP的作用 体现在函数调用的时候,在调用了一个函数后,堆栈中的内容一般是
参数n,参数n-1,参数n-2,。。。参数1,函数返回地址,当前EBP的值,本地参数1,本地参数2。。本地参数n
例子:
MyProc proc

push ebp  ;这就是为什么有当前EBP的值用于现场保护。为什么要那?想想如果嵌套调用函数
                ;会怎么样呢?
mov ebp,esp

sub esp,8

mov eax,dword ptr [ebp + 8]
sub eax,dword ptr [ebp + c]

add esp,8         ;为什么是8?因为例子里假设函数中有2个本地变量
pop ebp
ret 8            ;为什么是8?因为例子里假设函数传递了2个参数,
                   ;而且使用了stdcall,被调用函数要恢复堆栈

MyProc endp
每次都这样写多麻烦啊?不是要写死?
办法是人想的嘛,减少重复性劳动才是王道啊。。
于是就有了
enter xxx,yyy
leave这一对双胞胎了。。
enter的两个参数xxx表示函数所有本地参数占用的字节数,yyy表示嵌套级数,一般为0
enter 8,0替代程序黄色部分
leave替代程序蓝色部分
是不是简单多了?还是烦?。。。这个。。。。
masm提供了local宏,使用这个后函数可以简单的写为

MyProc proc Var1,Var2
local lVar1,lVar2

mov eax,Var1
sub eax,Var2
ret      ;这里可没8哦,local帮你搞定了

MyProc endp
这下简单了不?嘿嘿。是不是有点眼熟,有点象高级语言了吧。

有一个要注意,在一个函数内部中最好不要改变EBP的值,万不得已时一定要保护好现场,并尽快恢复。


另外还有几个知识点
声明函数
MyProc proto :DWORD,:DWORD
使用函数
invoke MyProc x,y

原文地址:https://www.cnblogs.com/goodloop/p/205836.html