饭后温柔

汉堡与老干妈同嚼 有可乐味
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

汇编知识点-数据传送,寻址和算术运算

Posted on 2013-08-02 18:01  饭后温柔  阅读(448)  评论(0编辑  收藏  举报

 

操作数类型

    立即操作数(immediate),寄存器操作数(register)和内存操作数(memory).

    直接内存操作数

      指令使用内存操作数实际使用的是操作数的地址.

      假设内存操作数val1位于偏移10400h处,那么把var1送al寄存器的汇编指令如下:

      mov AL, var1 

      MASM将指令汇编为 A0 00010400,机器指令第一个自己A0是操作码,剩下部分是var1的32位地址值.

      编写程序时使用纯数字地址表示内存操作数是可以的,使用var1这样的符号名更方便.

      表示直接内存操作数的其他记法:mov AL, [var1]   ;方括号暗示了要进行寻址操作

 

MOV

  2个操作数尺寸必须一致

  2个操作数不能同时为内存操作数

  目的操作数不能是CS, EIP, IP

  立即数不能直接送至段寄存器

 

  保护模式下,程序不应直接修改段寄存器.

 

  整数的零/符号扩展

  要么手动区分(eax, ax, ah, al).要么使用如下指令

  MOVZX dsc, src ;将源操作数的内容复制到目的操作数,并将该值零扩展至16位或32位.适用于无符号整数.

  MOVSX dsc, src ;将源操作数的内容复制到目的操作数,并将该值符号扩展至16位或32位.适用于有符号整数.

 

LAHF和SAHF

  LAHF将EFLAGS寄存器的低字节复制到AH寄存器.

  SAHF将AH寄存器的值复制到EFLAGS寄存器的低字节.

  

XCHG

  交换2个操作数的内容.有下面3个格式.

  XCHG reg, reg

  XCHG reg, mem

  XCHG mem, reg

  XCHG不接受立即操作数.其他规则与mov相同.

 

ADD, SUB

  操作数格式与mov相同. 影响标志:零标志,符号标志,溢出标志,辅助进位标志,奇偶标志. 

  补码表示法. 

  各个标志位状态改变的规则.

    

NEG 取反指令

 

和数据相关的操作符和伪指令

    OFFSET 

    返回数据标号的偏移地址.

    保护模式下,偏移是32位的,实地址模式下,偏移是16位的.

    

    ALGN伪指令

      ALGN  边界值           ; 将变量的位置按字节,字,双字或段边界对齐.

      边界值可以是1,2,4,或16.

      bval  BYTE  ?  ; 00404000

      ALGN  2

      wval  WORD ?    ; 00404002

      bval2  BYTE ?     ; 00404004

      ALGN  4

      dval   DWORD  ?   ; 00404008 

      

    PTR操作符

    重载操作数声明的默认尺寸.类似于c中的强制转换符.      

    myDouble  DWORD  12345678h

    mov ax, WORD PTR myDouble   ; ax=5678h

    wordList  WORD 5678h, 1234h

    mov eax, DWORD PTR wordList   ; eax=12345678h

    

    TYPE操作符

    按字节返回变量的大小.

 

    LENGTHOF

    计算数组中元素的数目.如果声明了一个跨多行的数组,LENGTHOF只把第一行的数据作为数组的元素.

    然而也可以再第一行的最后加一个逗号,以连接下一行的初始值.

    byte1  BYTE  10, 20, 30        ; 3

    array1  WORD  30 DUP(?), 0, 0     ; 32  

    array2  5 DUP(3 DUP(?) )          ; 15

    array3   BYTE 10, 20 ,30          ; 3

         BYTE 40, 50, 60

    array3   BYTE 10, 20 ,30,          ; 6

         BYTE 40, 50, 60

 

    SIZEOF操作符

    返回LENGTHOF和TYPE的乘积.

 

    LABEL伪指令

    插入一个标号并赋予其尺寸属性而无须分配任何世界的存储空间.

    常用法师位数据段内气候定义的变量提供一个别名以及一个不同的尺寸属性.(省略多处写PTR的繁琐)

    .data

    val16  LABEL  WORD

    val32  DWORD  12345678h

    mov  ax  val16    ;ax =  5678h

    mov  dx  [val16+2]    ; dx = 1234h

    有时需要用两个较小的整数构造一个较大的整数.

    .data

    LongValue LABEL  DWORD

    val1 WORD 5678h

    val2 WORD 1234h

    .code

    mov eax, LongValue    ;EAX = 12345678h

 

间接寻址

    处理数组时完全使用直接寻址是不切实际的.

    保护模式,间接操作数可以是任何用方括号括起来的任意的32位通用寄存器.

    实地址模式使用寄存器做间接操作数的话,只用使用SI, DI, BX, BP做寄存器.避免使用BP.

    .data

    val1 BYTE 10h

    .code

    mov esi OFFSET val1

    mov al, [esi]            ; al = 10h

    

    使用间接操作数的寄存器应进行初始化.否则保护模式下可能产生通用保护故障.实地址模式下引起未知问题.

    

    PTR:与间接操作数的联合使用.有时候在一条指令的上下文中,操作数的大小通常并不明确.

    inc   [esi]     ;错误.编译器并不知道ESI指向一个字节,一个字或其他尺寸的操作数

    inc  BYTE  PTR  [esi]    ;正确

 

    数组:

    .data

    array1 BYTE 10h, 20h, 30h

    .code

    move esi, OFFSET array1

    mov al, [esi]

    inc esi

    mov al, [esi]

    inc esi

    mov al, [esi]

 

    变址操作数

    变址操作数把常量和寄存器相加以得到一个有效地址.任何32位寄存器都可以作为变址寄存器.2种格式:

    constant[reg]

    [constant + reg]

    如:array[esi],  [array + esi], array[esi + 4]

    实地址模式只能使用SI,DI,BX,BP寄存器.避免使用BP.

  

    指针

            16位模式            32位模式

    NEAR指针:  相对数据段开始的16位偏移地址    相对于数据段开始的32位偏移地址     

    FAR指针:     32位的段-偏移地址          48位的段选择子-偏移地址

    默认为NEAR指针.

    arrayb   BYTE  10h, 20h, 30h, 40h

    arrayw  WORD  1000h, 2000h, 3000h

    ptrB  DWORD  arrayb

    ptrW     DWORD  arrayw

    还可试用TYPEDEF操作符:

    TYPEDEF允许创建用户自定义的类型.

    TYPEDEF的声明通常至于程序开始处,数据段之前.如:

    PMYTYPE   TYPEDEF PTR BYTE

    .data

    arrayB BYTE 10h, 20h, 30h, 40h

    ptr1 PMYTYPE ?          ;未初始化

    ptr2 PMYTYPE arrayB   ;指向数组    

      

    JMP指令

    无条件转义指令

    通常情况下JMP只能跳转到当前过程内的标号处

    JMP   目的地址

    top:

      ....

      JMP top

 

 

      LOOP指令    

      LOOP  目的地址

      ECX被自动用作计数器,每次循环减一.如果ECX等于0,则不跳转,否则一直跳转到目的地址.

      move   ecx,   5

       L1:

        inc ax

        loop  L1

      常犯错误为将ECX初始化为0.减一得到FFFFFFFF. 

      在寄存器不够用或者多重嵌套中,必须自己想办法保存恢复ECX的值.

 

      一个复制字符串的例子:

      INCLUDE Irvine32.inc

      .data

      source BYTE "This is the source string", 0

      target  BYTE SIZEOF source DUP(0), 0

      .code

      main PROC

        mov esi, 0

        mov ecx, SIZEOF source

      L1:

        mov al, source[esi]

        mov target[esi], al

        inc esi

        loop L1

        exit

      main ENDP

      END main