zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Dubbo之SPI实现原理详解
    Java SPI详解
    Java是如何实现自己的SPI机制的
    Dubbo的负载均衡原理解析
    Dubbo公开课
    【todo】什么是沟子函数
    一步一图,带你走进 Netty 的世界!
    https://github.com/xiaojiaqi/k8seasy_release_page
    mysql 8.0导致5.6数据后 :ERROR 1449 (HY000): The user specified as a definer ('mysql.infoschema'@'localhost') does not exist
    Ansible 日常使用技巧
  • 原文地址:https://www.cnblogs.com/goodloop/p/205836.html
Copyright © 2011-2022 走看看