zoukankan      html  css  js  c++  java
  • 使用MASM09 Win32汇编语言017

    使用MASM09

     

    让编程改变世界

    Change the world by program


     

    局部变量的使用

      [codesyntax lang="asm"]
    TestProc    proc   ;名为TestProc的子程序
    	local        @loc1:dword, @loc2:word
    	local        @loc3:byte    ;用local语句定义了3个变量
    
    	mov eax, @loc1    ;对应类型进行存储,然后返回
    	mov ax, @loc2
    	mov al, @loc3
    	ret
    TestProc    endp
    [/codesyntax]   我们来看看它反汇编之后是什么样子的: [codesyntax lang="asm"]
    :00401000   55        push ebp
    :00401001   8BEC      mov ebp, esp
    :00401003   83C4F8    add esp, FFFFFFF8
    :00401006   8B45FC    mov eax, dword ptr [ebp-04]
    :00401009   668B45FA  mov ax, word ptr [ebp-06]
    :0040100D   8A45F9    mov al, byte ptr [ebp-07]
    :00401010   C9        leave
    :00401011   C3        ret
    [/codesyntax]   可以看到,反汇编后的指令比源程序多了前后两段指令,它们是: [codesyntax lang="asm"]
    :00401000 55          push ebp
    :00401001 8BEC        mov ebp, esp
    :00401003 83C4F8      add esp, FFFFFFF8
    
    :00401010 C9          leave
    [/codesyntax]   这些就是使用局部变量所必需的指令,分别用于局部变量的准备工作和扫尾工作。   【分析过程】 当调用者执行了call TestProc指令后,CPU把返回的地址(当前地址)压入堆栈,再转移(jmp)到子程序执行。 esp在程序的执行过程中可能随时用到,不可能用esp来随时存取局部变量,ebp寄存器(可以理解为小三)是以堆栈段为默认数据段的,所以,可以用ebp做指针指向堆栈替代esp。 于是,在初始化前,先用一句push ebp指令把原来的dbp保存起来,然后把esp的值放到ebp中。 (介绍局部变量怎么腾出空间的)再后面就是堆栈中预留空间了,由于堆栈是向下增长的。所以要在esp中加一个负值,FFFFFFF8就是-8。   我们来考虑另一个问题:一个dword加一个word加一个byte不是7吗,为什么刚刚我们在堆栈为局部变量让出了8个字节的空间呢? 这是因为在80386处理器中,以dword (32位)为界对齐时存取内存速度最快,所以MASM宁可浪费一个字节,执行了这3句指令后,初始化完成,就可以进行正常的操作了,从指令中可以看出局部变量在堆栈中的位置排列。   在程序退出的时候,必须把正确的esp设置回去,否则,ret指令会从堆栈中取出错误的地址返回,看程序可以发现,ebp就是正确的esp值。 因为子程序开始的时候已经有一句mov ebp,esp,所以要返回的时候只要先mov esp,ebp,然后再pop ebp,堆栈就是正确的了。   在80386指令集中有一条指令可以在一句中实现这些功能,就是leave指令,所以,编译器在ret指令之前只使用了一句leave指令。 明白了局部变量使用的原理,就很容易理解使用时的注意点:ebp寄存器是关键(第一次听说小三是关键)   因为它起到保存原始esp的作用,并随时用做存取局部变量的指针基址,所以在任何时刻,不要尝试把ebp用于别的用途,否则会带来意想不到的后果。(在任何时候不要做对不起小三的事情,不然后果很严重 T_T)  

    闲言碎语

      Win32汇编中局部变量的使用方法可以解释一个很有趣的现象:在DOS汇编的时候,如果在子程序中的push指令和pop指令不配对,那么返回的时候ret指令从堆栈里得到的肯定是错误的返回地址,程序也就死掉了。 但在Win32汇编中,push指令和pop指令不配对可能在逻辑上产生错误,却不会影响子程序正常返回,原因就是在返回的时候esp不是靠相同数量的push和pop指令来保持一致的,而是靠leave指令从保存在ebp中的原始值中取回来的。 也就是说,即使把esp改得一塌糊涂也不会影响到子程序的返回,当然,窍门就在ebp,把ebp改掉,程序就玩完了!  

    局部变量的初始化值

      显然,局部变量是无法在定义的时候指定初始化值的,因为local伪指令只是简单地把空间给留出来,那么开始使用时它里面是什么值呢? 和全局变量不一样,局部变量的初始值是随机的,是其他子程序执行后在堆栈里留下的垃圾(因为我们知道,腾出空间只是改变栈指针esp)。 所以,对局部变量的值一定要初始化,特别是定义为结构后当参数传递给API函数的时候。   在API函数使用的大量数据结构中,往往用0做默认值,如果用局部变量定义数据结构,初始化时只定义了其中的一些字段,那么其余字段的当前值可以是编程者预想不到的数值,传给API函数后,执行的结果可能是意想不到的,这是初学者很容易忽略的一个问题。 所以最好的办法是:在赋值前首先将整个数据结构填0,然后再初始化要用的字段,这样其余的字段就不必一个个地去填0了,RtlZeroMemory这个API函数就是实现填0的功能的。 [buy] 获得所有教学视频、课件、源代码等资源打包 [/buy] [Downlink href='http://urlxf.qq.com/?qUVr227']视频下载[/Downlink]
  • 相关阅读:
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第三节 梯度下降法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第二节 线性回归算法 (下)实操篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第二节 线性回归算法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第一节 KNN算法 (下)实操篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第一节 KNN算法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第二章 pandas 第五节 Getting Started with pandas
    Oracle数据库安装和授权
    c# 如何获取JSON文件以及如何获取Config文件(framework 和 net .Core)
    C#Core查询数据库存储EXCEL文件
    如何在WINDOW系统下编译P12证书制作
  • 原文地址:https://www.cnblogs.com/LoveFishC/p/3846157.html
Copyright © 2011-2022 走看看