汇编笔记_1

汇编语言-寄存器

IA-32位通用寄存器

  • 8个32位寄存器

    EAX, EBX, ECX, EDX,

    ESI, EDI , EBP, ESP

  • 8个16位寄存器
    AX,BX,CX,DX
    SI,DI,BP,SP
    
  • 8个8位寄存器
    AH,BH,CH,DH
    AL,BL,CL,D、L
    

汇编子程序

  • 子程序举例

    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
    
    反汇编后:
        :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
    
  • 子程序详解

    子程序定义:

    子程序名  proc
    loacl     局部变量;
    
    ret
    子程序名  endp
    

    子程序汇编解释:

        :00401000   55                   push ebp
        :00401001   8BEC                 mov ebp, esp
        :00401003   83C4F8               add esp, FFFFFFF8
        
        
        :00401010    C9                      leave
    

    汇编多出来这几句,

    当调用者执行了call TestProc指令后,CPU把返回的地址(当前地址)压入堆栈,再转移(jmp)到子程序执行。

    esp在程序的执行过程中可能随时用到,不可能用esp来随时存取局部变量,ebp寄存器是以堆栈段为默认数据段的,所以,可以用ebp做指针指向堆栈替代esp

    于是,在初始化前,先用一句push ebp指令把原来的ebp保存起来,然后把esp的值放到ebp中。

    由于上面的例子子程序,申请了7个字节的空间,而堆栈是向下增长的。所以要在esp中加一个负值,FFFFFFF8就是-8。

    因为在80386处理器中,以dword (32位)为界对齐时存取内存速度最快,所以MASM宁可浪费一个字节,使用8个字节的空间,而不使用7个字节。

    leave命令相当于
    mov esp , ebp
    pop ebp
    
  • 局部变量的使用

    注意: ebp寄存器是关键

    因为它起到保存原始esp的作用,并随时用做存取局部变量的指针基址,所以在任何时刻,不要尝试把ebp用于别的用途,否则会带来意想不到的后果

    • 局部变量定义的时候

    局部变量在定义的时候,loacl指令知识单纯的留出空间,而没有存放值,变量里面是其他程序在堆栈执行后留下的垃圾(因为我们知道,腾出空间只是改变栈指针esp),所以对局部变量的值一定要初始化。

    • 局部变量填0函数
    RtlZeroMemory
    

汇编变量

  • 变量的大小
    在这里插入图片描述

  • 汇编不会强制转换类型

    在汇编中,要注意变量的大小

    例如,以db方式定义一个缓冲区:
                   szBuffer       db       1024 dup (?)
    然后      mov ax,szBuffer
    编译器会报一个错:
     error A2070: invalid instruction operands
    
    意思是无效的指令操作,为什么呢?因为szBuffer是用db定义的,而ax的
    尺寸是一个word,等于两个字节,尺寸不符合。
    
  • 汇编变量的使用–以不同的类型访问变量

      					.data
           bTest1         db          12h
           wTest2        dw          1234h
           dwTest3      dd          12345678h
                               ……
                        .code
               mov        al, bTest1
               mov        ax, word ptr bTest1
               mov        eax, dword ptr bTest1
    

    解释与注意;

    在这里要注意的是,指定类型的参数访问并不会去检测长度是否溢出

    在MASM中,如果要用指定类型之外的长度访问变量,必须显式地指出要访问的长度,这样编译器忽略语法上的长度检验,仅使用变量的地址。

    使用的方法是: 类型 ptr 变量名
    类型可以是byte, word, dword, fword, qword, real8和real10。

    汇编解释:

    上面的程序片断,每一句执行后寄存器中的值是什么呢?
    mov al, bTest1 这一句很显然使 al 等于 12h,下面的两句呢,ax 和 eax难道等于 0012h 和00000012h吗?
    实际运行结果是 3412h 和 78123412h,为什么呢?

    ;.data段中的变量
    :00403000    12 34 12 78 56 34 12 ... 
                        │  │       │
                        │  │       └──→    dwTest3
                        │  └──────→    wTest2
                        └─────────→ bTest1
    ;.code段中的代码
    :00401000 A000304000	  mov al, byte ptr [00403000]
    :00401005 66A100304000 	  mov  ax, word ptr [00403000]
    :0040100B A100304000 	  mov eax, dword ptr [00403000]
    
    

    刚才这个例子说明了汇编中用ptr强制覆盖变量长度的时候,实质上是只用了变量的地址而禁止编译器进行检验。
    编译器并不会考虑定界的问题,程序员在使用的时候必须对内存中的数据排列有个全局概念,以免越界存取到意料之外的数据。

  • 汇编movzx指令

    作用:

    把bTest1的一个字节扩展到一个字或一个双字再放到ax 或 eax中,高位保持0而不是越界存取到其他的变量.

    例子;

      	.data
           bTest1         db          12h
           wTest2        dw          1234h
           dwTest3      dd          12345678h
           .code
          movzx            ax,bTest1         ; ax == 0012h
           movzx            eax,bTest1       	; eax == 00000012h
           movzx            eax,cl               ; eax == 000000(cl)
           movzx            eax,ax              ; eax == 0000(ax)
    
  • 变量的使用–变量的尺寸和数量

    sizeof和lengthof伪指令

    使用格式:

           sizeof      变量名、数据类型或数据结构名
           lengthof   变量名
    

    他们的区别是:

    sizeof 伪指令可以取得变量、数据类型或数据结构以字节为单位的长度,

    然而 lengthof 则可以取得变量中数据的项数。

    例子:

       .data
       stWndClass           WNDCLASS         <>
           szHello           db                         ‘Hello,world!’,0
           dwTest           dd                         1,2,3,4
                                 ……
                                 .code
                                 ……
                                 mov eax,  sizeof stWndClass
                                 mov ebx,  sizeof WNDCLASS
                                 mov ecx,  sizeof szHello
                                 mov edx,  sizeof dword
                                 mov esi,  sizeof dwTest
    
    

    执行结果;

    执行后eax 的值是stWndClass 结构的长度:40
    
    ebx同样是:40
    
    ecx的值是Hello,world! 字符串的长度加上一个字节的0结束符:13
    
    edx的值是一个双字的长度:4
    
    esi等于4个双字的长度:16
    
    假设
    如果把所有的sizeof 换成 lengthof,那么eax会等于1,因为只定义了1项WNDCLASS
    
    而ecx同样等于13
    
    esi则等于4、
    
    lenghof WNDCLASST 和 lengthof dword 是非法的用法,编译程序会报错。
    

    注意:

    sizeof 和lengthof 的数值是编译时产生的,由编译器传递到指令中去,上边的指令最后产生的代码就是:
                      mov  eax, 40
                      mov  ebx, 40
                      mov  ecx, 13
                      mov  edx, 4
                      mov  esi, 16
    
    • MASM 中的变量定义只认一行
    如果为了把Hello和World分两行定义,szHello是这样定义的:
    
           szHello       db         ‘Hello’, odh, oah
                             db         ‘World’, 0
    那么 sizeof szHello 是多少呢?
    注意!是7,而不是13。MASM 中的变量定义只认一行,后一行db  ‘World’, 0 实际上是另一个没有名称的数据定义,编译器认为sizeof szHello 是第一行字符的数量
    

    虽然把 szHello 的地址当参数传给 MessageBox 等函数显示时会把两行都显示出来,但严格地说这是越界使用变量。
    虽然在实际的应用中这样定义长字符串的用法很普遍,因为如果要显示一屏幕帮助,一行是不够的。
    但要注意的是:要用到这种字符串的长度时,千万不要用 sizeof 去表示,最好是在程序中用lstrlen 函数去计算。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值