绝大部分机器指令都是进行数据处理的指令,处理可分为3类:读取、写入、运算。在机器指令这一层来说,并不关心数据的值是多少,而关心指令执行前一刻,它将要处理的数据所在的位置。
指令在执行前,所要处理的数据可以在三个地方:CPU内部、内存、端口。
汇编程序中数据的位置这样表达:
一、立即数
即直接包含在机器指令中的数据(执行前在CPU缓冲器中)。例如:
mov ax,1
add bx,1000h
or bx,00100000b
mov al,'a'
二、寄存器
指要处理的数据在寄存器中,在汇编指令中给出相应的寄存器。例如:
mov ax,bx
add ds,ax
push bx
mov ds:[0],bx
push ds
mov ss,ax
mov sp,ax
三、段地址(SA)和偏移地址(EA)
指令要处理的数据在内存中,在汇编指令中可用[x]的格式给出EA,SA在某个段寄存器中。
存放段地址的寄存器可以是默认的,例如:
mov ax,[0]
mov ax,[di]
mov ax,[bx+8]
mov ax,[bx+si]
mov ax,[bx+si+8]
这些指令,段地址默认在ds中;(bx)
mov ax,[bp]
mov ax,[bp+8]
mov ax,[bp+si]
mov ax,[bp+si+8]
这些指令,段地址默认在ss中。(bp)
存放段地址的寄存器也可以是显性给出的,例如:
mov ax,ds:[bp] ;ax=ds*16+bp
mov ax,es:[bx] ;ax=es*16+bp
mov ax,ss:[bx+si] ;ax=ss*16+bx+si
mov ax,cs:[bx+si+8] ;ax=cs*16+bx+si+8
寻址方式:
寻址方式 | 含义 | 名称 | 常用格式举例 |
---|---|---|---|
[idata] | EA=idata;SA=(ds) | 直接寻址 | [4],[5],[10] |
[bx] | EA=(bx);SA=(ds) | 寄存器间接寻址 | [bx] |
[si] | EA=(si);SA=(ds) | 寄存器间接寻址 | |
[di] | EA=(di);SA=(ds) | 寄存器间接寻址 | |
[bp] | EA=(bp);SA=(ss) | 寄存器间接寻址 | |
[bx+idata] | EA=(bx)+idata;SA=(ds) | 寄存器相对寻址 | 用于结构体:[bx].idata |
[si+idata] | EA=(si)+idata;SA=(ds) | 寄存器相对寻址 | 用于数组:idata[si] |
[di+idata] | EA=(di)+idata;SA=(ds) | 寄存器相对寻址 | 用于数组:idata[di] |
[bp+idata] | EA=(bp)+idata;SA=(ss) | 寄存器相对寻址 | 用于二维数组:[bx][idata] |
[bx+si] | EA=(bx)+(si);SA=(ds) | 基址变址寻址 | 用于二维数组:[bx][si] |
[bx+di] | EA=(bx)+(di);SA=(ds) | 基址变址寻址 | |
[bp+si] | EA=(bp)+(si);SA=(ss) | 基址变址寻址 | |
[bp+di] | EA=(bp)+(di);SA=(ss) | 基址变址寻址 | |
[bx+si+idata] | EA=(bx+si+idata);SA=(ds) | 相对基址娈址寻址 | 用于表格(结构)中的数组项:[bx].idata[si] |
[bx+di+idata] | EA=(bx+di+idata);SA=(ds) | 相对基址娈址寻址 | 用于二维数组:idata[bx][si] |
[bp+si+idata] | EA=(bp+si+idata);SA=(ss) | 相对基址娈址寻址 | |
[bp+di+idata] | EA=(bp+di+idata);SA=(ss) | 相对基址娈址寻址 |
指明要处理的数据有多长:
8086CPU中,可以处理两种尺寸的数据,byte和word。所以在机器指令中要指明指令进行的是字操作还是字节操作。
一、通过寄存器名指明要处理的数据的尺寸
可以用8位寄存器来表示byte,如:al;16位的寄存器来表示word,如:ax。
例如:
mov ax,1
mov bx,ds:[0]
mov ds,ax
mov ds:[0],ax
inc ax
add ax,1000
其中ax指明了是字操作。
mov ax,1
mov al,bl
mov al,ds:[0]
mov ds:[0],al
inc ax
add al,100
其中al指明了是字节操作。
二、在没有寄存器名存在的情况下,用操作符X ptr指明内存单元的长度,X在汇编指令中可以为word或byte。
例如:
mov word ptr ds:[0],1
inc word ptr [bx]
inc word ptr ds:[0]
add word ptr [bx],2
其中,用word ptr指明了指令访问的内存单元是一个字单元。
mov byte ptr ds:[0],1
inc byte ptr [bx]
inc byte ptr ds:[0]
add byte ptr [bx],2
其中,用byte ptr指明了指令访问的内存单元是一个字节单元。
在没有寄存器参与的内存单元访问指令中,用word ptr或byte ptr显性地指明所要访问的内存单元的长度是很必要的。否则,CPU无法得知所要访问的单元是字单元,还是字节单元。
三、其他方法
有些指令默认了访问是字单元还是字节单元,如:push[1000h]就不用指明访问的是字单元还是字节单元,因为push指令只进行字操作。
8086CPU提供的如:[bx+si+idata]的寻址方式为结构化数据的处理提供了方便。
一个结构化的数据包含了多个数据项而数据项的类型又不同,有的是字型数据,有的是字节型数据,有的是数组(字符串)。
我们可以用[bx+idata+si]的方式来访问结构体中数据。用bx来定位整个结构体,用idata来定位结构体中的某一个数据项,用si来定位数组项中的每个元素。汇编提供了更贴切的书写方式,如:[bx].idata、[bx].idata[si]
div指令
div是除法指令,使用要注意以下问题:
- 除数:有8位和16位两种,在一个reg或内存单元中;
- 被除数:默认放在AX或DX和AX中,如果除数为8位,被除数则为16位,默认在AX中存放;如果除数为16位,则被除数为32位,在DX和AX中存放,DX存放高16位,AX存放低16位。
- 结果:如果除数为8位,则AL存储除法操作的商,AH存储余数;如果除数为16位,则AX存储除法操作的商,DX存放余数。
格式为:
div reg
div 内存单元
dd指令:
dd指令用来定义dword(双字)型数据。占两个字,32字节。
dup指令:
dup是一个操作符,同db,dw,dd等一样,也是由汇编器识别处理的符号。它是和db,dw,dd等数据定义伪指令配合使用的,用来进行数据的重复。
使用:
db 3 dup(0)
定义了3个字节,值都为0;
db 3 dup(0,1,2)
定义了9个字节,值为0 1 2 0 1 2 0 1 2