从今天起开始学习intel汇编(二)数据传送,寻址和算术运算

一 数据传送指令

  1.操作数类型

    主要包括三种操作数:立即操作数,寄存器操作数

    

  1.1直接使用内存操作数

    变量名仅仅是对数据段内偏移地址的引用,下面声明了一个包含数字10H的一个字节被置于数据段内

    .data

    var1 BYTE 10h

     指令使用内存操作数实际上还是使用的操作数的地址,假设var1位于0x10400处,那么将var1送入AL寄存器的汇编指令如下:

    MOV AL, var1

    编译器将这段指令翻译成

    A0 00010400

    机器指令的第一个字节是操作码,剩下的部分是变量var1的十六进制的地址值,编写程序时可以使用纯数字地址表示,不过使用变量名更方便

    还可以使用这种方法表示

    mov al, [var1]

  2.mov指令

    mov destination, source

    要遵循以下规则

    两个操作数的尺寸必须一致   两个操作数不能同时为内存操作数

    目的操作数不能使CS,EIP和IP

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

    在运行与保护模式下,不应该直接修改段寄存器,一般来说,段寄存器仅由实模式下的程序使用,对段寄存器可以有以下两种格式

    mov r/m16, sreg

    mov sreg, r/m16

    单条MOV指令不能把数据从一个内存位置直接移动到另外一个内存位置, 可以先把内存中的数据移动到寄存器,然后在移动到另外一个内存位置

  3.整数的零,符号扩展

    复制较小值至较大值中:

    movzx指令将源操作数的内容复制到目的操作数中,并将该值零扩展到16位或32位,该指令仅适用于无符号整数。

    movzx r32, r/m8

    movzx r32, r/m16

    movzx r16, r/m8   目的操作数必须是寄存器

    

    movsx将源操作数的内容复制到目的操作数中,并将该值符号扩展到16位或32位。该指令只能用于有符号整数:

    movsx r32, r/m8

    movsx r32, r/m16

    mov sx r16, r/m8

  4.LAHF和SAHF

    LAHF指令将EFLAGS寄存器的低字节复制到AH寄存器中,被复制的标志包括符号标志,零标志,辅助进位标志,奇偶标志和进位标志。

    SAHF指令复制AH寄存器的值至EFLAGS寄存器的低字节。

  5.XCHG

    XCHG指令交换两个操作数的内容,它有下面三种格式:

    XCHG reg, reg

    XCHG reg, mem

    XCHG mem, reg

    XCHG不接受立即数, 其他规则跟MOV指令的操作数遵循同样的规则。

    要交换2个内存的值时, 比较方便:

    mov eax, var1

    XCHG eax, var2

    mov var2, eax

  6.直接偏移操作数

    在变量名后面加上一个偏移值, 可以创建直接偏移操作数,可以通过它来访问没有显示标号的内存地址:

    array1 BYTE 10h, 20h, 30h, 40h

    如果 mov 指令使用array1作为源操作数,将把数组的第一个字节送到AL

    mov al, array1

    可以通过在array1的偏移地址上加1来访问数组中的第二个字节

    MOV al, [array1 + 1]

   同样加2可以访问第三个字节

    mov al, [array + 2]

    但是编译器不做范围检查,因此对数组的引用要小心

    字和双字数组做地址加减是,要乘上元素大小

    array1 word 100h, 200h, 300h

    访问第二个就需要mov ax, [array1 + 2]

    访问第三个 mov ax, [array1 + 4]

二 加法和减法

  1. INC和DEC指令

    INC和DEC指令从操作数中加1和减1:

    INC reg/mem

    dec reg/mem

  2.ADD指令

    ADD指令将同大小的源操作数和目的操作数相加:

    ADD 目的操作数,源操作数

    加法操作并不会改变源操作数, 相加的结果存储在目的操作数中,其操作数的格式与MOV指令的操作数格式相同

    影响标志:进位标志, 零标志,符号标志, 溢出标志, 辅助进位标志和奇偶标志

  3.SUB指令

    SUB指令将源操作数从目的操作数中减掉,格式与ADD和MOV一样

    影响标志:进位标志, 零标志,符号标志, 溢出标志, 辅助进位标志和奇偶标志

  4.NEG指令

    通过将数值转换为对应的补码而求得其相反数(这里书上说的有点问题啊, 求补和求补码不一样啊, 求补是求负数, 补码是补码,正数的补码是其本身)

    注意这里是求补的意思,也就是求该数的负数

    NEG reg/mem

  5.加法和减法影响的 标志

    进位标志用于表示无符号整数运算是否发生溢出, 假设指令的目的操作数为8位,如果大于了1111111那么进位标志就置位

   标志位CF是进位标志位(Carry Flag)。
   当两个数相加时,若最高位向上形成进位,则CF=1;
   当两个数相减时,若最高位向上形成借位,则CF=1;
   当两个无符号数相乘时,若乘积的高一半为0,则CF=0;
   当两个带符号数相乘时,若乘积的高一半是低一半的符号扩展,则CF=0.

    溢出标志用于表示有符号整数运算是否溢出,比如负数和负数, 正数和正数做加法 结果的符号跟操作数不同就产生了溢出

    零标志判断结果是否为0

    符号位用于判断运算结果是否为负

    奇偶标志结果最低有效字节内中为1的位数为偶数置位

    辅助进位用户第三位向高位产生进位1时置位,主要用于BCD码

    无符号运算影响:零标志, 进位标志, 辅助进位标志

    CPU如何检查溢出:将向最高有效位进位值和最高有效位的进位值进行异或。

    NEG指令如果对最小负数进行求反, 那么会照成溢出, -127求反那么的128, 128溢出

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

  1.OFFSET 操作符

    返回数据标号的偏移地址, 偏移地址代表标号距离数据段开始的距离,单位是以字节计算的。

  2.ALIGN 指令

    将变量的位置按字节,字,双子对齐。

     ALIGN  边界值

    边界值必须是1,2,4,16,后面一个边界值是前面一个边界值得倍数

  3.PTR操作符

    可以使用PTR操作符来重载操作数声明的默认尺寸, 这在试图以不同变量声明时所使用的尺寸属性来访问变量时非常有用

    .data

    muDouble DWORD 12345678h

    .code

    mov ax, myDouble;  错误

    mov ax, WORD PTR myDouble

  4.TYPE操作符

    返回按字节计算的变量的单个元素的大小

    TYPE var

  5.LENGTHOF

    计算组中元素个数,元素由出现在同一行的值定义:

    .data

    byte1 BYTE 10, 20, 30

    array1 WORD 30 DUP(?), 0, 0

    array2 WORD 5 DUP(3 DUP(?))

    array3 DWORD 1, 2,3 ,4

    digitStr BYTE "12345678", 0

    LENGTHOF byte1 3

    LENGTHOF array1 30 + 2

    LENGTHOF array2 5*3

    LENGTHOF array3 4

    LENGTHOF digitStr 9

    如果声明了跨多行的数组,值返回第一行的元素个数, 可以加逗号连接下一行初始值

  6.SIZEOF操作符返回值等于LENGTHOF喝TYPE返回值的乘积

  7.LABEL指令允许插入一个标号并赋予其后所定义的变量尺寸,而无需分配任何内存空间,就是给后面的变量去一个别名和不同尺寸类型

    .DATA

    var1 LABLE WORD

    var2 DWORD 12345678h

    .code

    mov ax, val1             var1 是后面的数据的别名, 但是数据类型为WORD

    mov dx, [val1 + 2]

  四 间接操作数

  在处理数组时,完全使用间接寻址是不且实际的, 我们不可能为每一个数组的每个元素都提供一个不同的标号,也不大可能使用非常多的常量偏移去寻址数组的各个元素,处理数组的唯一可行的方法是用寄存器作为指针并操纵寄存器的值

  1.间接操作数

    可以使用方括号括起任意的32位通用寄存器,寄存器里面存放着数据的偏移

    .data

    var1 BYTE 10h

    .code

    mov esi, OFFSET var1

    mov al, [esi]

    mov [esi], bl

   2.使用PTR与间接操作数组合

    有时候在一条指令上下文中,操作数大小通常不明确

    inc [ESI]   错误, ESI地址数据类型并不确定

    inc BYTE PTR [esi]

  3.变址操作数

    把常量和寄存器相加以得到一个地址。

    第一种是把变量的名字和寄存器集合起来,变量的名字代表变量偏移地址常量,

    .data

    arrayb BYTE 10h, 20h, 30h

    .code

    mov esi, 0

    mov al, [arrayb + esi]

    另一种是变址寄存器和常量偏移联合起来使用,不过是用变址寄存器存放数组基地址,用常量表示偏移。

    .data

    arrayW WORD 1000h, 2000h, 3000h

    .code 

    mov esi, OFFSET arrayW

    mov ax, [esi + 2]    ;2000H

    带比例因子的变址寻址

    .data

    arrayD DWORD 1, 2, 3, 4

    .code

    mov esi, 3

    mov eax, arrayD[esi*4]

    用上TYPE更灵活

    mov esi, 3

    mov eax, arrayD[esi * TYPE arrayD]

  4.指针

    包含其他变量地址的变量称为指针变量

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

    FAR:48位的段选择子

  5.TYPEDEF

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

    PBYTE TYPEDEF PTR BYTE

    .data

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

    ptr1 PBYTE ?

    ptr2 PBYTE arrayB

  6.使用指针访问数据的例子

    INCLUDE Irvine32.inc
    PBYTE TYPEDEF PTR BYTE
    PWORD TYPEDEF PTR WORD
    PDWORD TYPEDEF PTR DWORD
    .data
    arrayB BYTE 10h, 20h, 30h
    arrayW WORD 1, 2, 3
    arrayD DWORD 4, 5, 6
    ptr1 PBYTE arrayB
    ptr2 PWORD arrayW
    ptr3 PDWORD arrayD
   .code
    main PROC
mov esi ,ptr1
xor eax, eax
mov al, [esi]
mov esi, ptr2
xor ebx, ebx
mov bx, [esi]
mov esi, ptr3
mov ecx, [esi]
call DumpRegs
exit
    main ENDP
    END main

五 JMP和LOOP指令

  1. jmp指令

    jmp指令导致向代码段的目的地址做无条件转移, 标识目的地址的代码标号将由汇编器翻译成偏移地址, JMP指令格式是:

    JMP 目的地址

  2.LOOP 目的指令

     重复执行一块语句, 执行次数是特定的, ECX是自动用作计数器, 在每次循环之后减1格式如下

    loop 目的地址

    LOOP指令的执行分成两步, 首先ECX减1, 接着与0比较, 如果ECX不等于0,跳转到目的地址, 如果ECX等于0, 则不发生跳转

    mov ax, 0

    mov ecx, 5

    L1:

        inc ax

        loop L1

    执行完后 ax = 5

    循环的目的地址与当前地址只能在距-128~+127字节的范围内, 机器指令的平均大小是3字节左右,因此一个循环平均最多只能包含大约42条指令

    例子:整数数组求和

    INCLUDE Irvine32.inc
    .data
    arrayD DWORD 10h, 20h, 30h
    .code
    main PROC
mov ecx, LENGTHOF arrayD
mov eax, 0
mov edi, OFFSET arrayD
    L1:
add eax, [edi]
add edi, TYPE arrayD
    loop L1
call DumpRegs
exit
    main ENDP
    END main

    

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值