数据传送、寻址和算术运算
4.1 数据传送指令
4.1.1 简介
第一段一大推,就是为了说明汇编相比高级语言来说比较麻烦需要注意很多细节,但是换来的好处是给开发者带来了更大的灵活性。
读者如果肯花时间彻底掌握本章内容,那么本书的后续部分将更容易学习。对以后变得越来越复杂的例子程序的理解,将在很大程度上依赖于对本章提供的基本工具的掌握。
4.1.2 操作数类型
本章讲述三种类型的操作数:立即操作数(immediate)、寄存器操作数(register)和内存操作数(memory)。在这三者当中,只有内存操作数稍微有点复杂。下表列出的操作数的简写符号是从Intel IA-32手册上摘录下来的。
4.1.3 直接内存操作数
3.4节已经解释过,变量名仅仅是对数据段内偏移地址的引用。下面的声明表示一个包含数字10h的字节被置于数据段内:
.data
var1 BYTE 10h
指令使用内存操作数时实际上使用的书操作数的地址。假设var1位于偏移10400h处,那么把var1送AL寄存器的汇编指令如下:
mov AL,var1
MASM将这条指令汇编成如下的机器指令:
A0 00010400
机器指令的第一个字节是操作码,剩下的部分是变量var1的十六进制的32位地址值。编写程序时仅使用纯数字地址表示内存操作是可以的,不过像var1这样的符号名使得引用内存时更加方便一些。
一些开发者更喜欢使用下面的方式表示直接操作数,因为方括号按时了要进行寻址操作:
mov al,[var1]
MASM允许使用这种方式。mov al,[var1+5] (这称为直接偏移操作数。)
4.1.4 MOV指令
MOV指令从源操作数向目的操作数复制数据。作为数据传送指令,几乎每个程序中都会用到MOV。其基本格式是:第一个操作数是目的(destination)操作数,第二个操作数是源(source)操作数:
MOV destination,source
指令运行后,目的操作数的内容被改变而源操作数的内容保持不变。
MOV指令对操作数的使用是非常灵活的,只要遵循以下规则即可:
1.两个操作数的尺寸必须一致。
2.两个操作数不能同时为内存操作数。
3.目的操作数不能是CS,EIP和IP。
4.立即数不能直接送至段寄存器。
下面是MOV指令格式列表,但寄存器(reg)是不包括段寄存器的:
MOV reg ,reg
MOV mem ,reg
MOV reg ,mem
MOV mem ,imm
MOV reg ,imm
在运行于保护模式下时,程序不应直接修改段寄存器。一般来说,段寄存器仅应由实地址模式下运行的程序使用,对段寄存器的操作可以有一下两种格式,唯一的例外是CS不能用作目的操作数:
MOV r/m16 ,sreg
MOV sreg ,r/m16
内存之间的移动:单条MOV指令不能把数据从一个内存位置直接移动到另外一个内存位置。
作为一种替代方法,在送至目的操作数之前,可以先把源操作数移入一个寄存器中:
.data<