《汇编语言(第四版)》—王爽 第八章数据处理的两个基本问题
第八章数据处理的两个基本问题
引言
计算机是进行数据处理、运算的机器,那么就有两个基本的问题:
- 处理的数据在什么地方
- 要处理的数据有多长
对于这两个问题,在机器指令中必须给出明确或者隐含的说明,否则计算机将无法工作
本章中我们就要针对8086CPU进行这两个问题的讨论。
为了使得描述更加的简洁,我们定义的描述性符号:reg(寄存器)和sreg(段寄存器)
reg的集合包括:ax,bx,cx,dx,ah,al,bh,bl,ch,cl,dh,dl,sp,bp,si,di
sreg的集合包括:ds,ss,cs,es(扩展段)
8.1、bx、si、di、bp
1> 在8086CPU中只有这四个寄存器(bx、si、di、bp)可以用在[…]中进行内存地址的寻址
正确的表示形式:
- mov ax,[bx]
- mov ax,[bx+si]
- mov ax,[bx+di]
- mov ax,[bp]
- mov ax,[bp+si]
- mov ax,[bp+di]
错误的表示形式:
- mov ax,[cx]
- mov ax,[ax]
- mov ax,[ds]
2> 在[…]中,这四个寄存器可以单独出现,或者只能以四种组合形式出现
- bx和si
- bx和di
- bp和si
- bp和di
错误的用法:
- mov ax,[bx+bp]
- mov ax,[si+di]
3> 只要在[…]中使用寄存器bp,而指令中没有显性的给出段地址,段地址就默认在ss中
- mov ax, [bp]
含义: (ax)= ( (ss)*16+(bp) ) - mov ax, [bp+idata]
含义:(ax)= ( (ss)*16+(bp)+idata) - mov ax , [bp+si]
含义:(ax)= ( (ss)*16+(bp)+(si) ) - mov ax,[bp+si+idata]
含义: (ax)= ( (ss)*16+(bp)+(si)+idata)
8.2、机器指令处理的数据所在的位置
绝大多数的机器指令都是进行数据的处理的指令,处理大致分为三类:读取,写入,运算
机器指令并不关心数据的值是多少,而关心指令执行前一刻,它将要处理的数据在什么位置
指令执行前,所要处理的内存可以在三个地方:CPU内部,内存,端口
8.3、汇编语言中数据位置的表达
在汇编语言中如何表示数据的位置?
- 立即数(idata)
- 对于直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中)
- 寄存器
- 指令要处理的数据在寄存器中
- 段地址(SA)和偏移地址(EA)
- 指令要处理的数据在内存中
- 存放段地址的寄存器可以是默认的
- mov ax,[bx] 段地址默认在ds中
- mov ax,[bx+si+idata] 段地址默认在ds中
- mov ax,[bp+si+idata] 段地址默认在ss中
- 存放段地址的寄存器也可以显性的给出
- mov ax,ds:[bp] 含义:(ax) = ((ds) * 16 + (bp))
- mov ax,es:[bx] 含义:(ax) = ((es) * 16 + (bx))
- mov ax,cs:[bx+si+idata] 含义:(ax)=((cs)*16+(bx)+(si)+idata)
8.4、寻址方式
定位内存地址的方法一般被称为寻址方式
直接寻址:
寄存器间接寻址
寄存器相对寻址:
基址变址寻址:
相对基址变址寻址:
8.5、指令要处理的数据有多长
8086CPU的指令可以处理为两中尺寸的数据,byte和word,所以在机器指令中要指明,指令进行的是字操作还是字节操作
确定指令要处理的数据有多长的方法:
-
通过寄存器名指明要处理的数据的尺寸
- 字操作
- 字节操作
- 字操作
-
在没有寄存器名存在的时候,用操作符X ptr 指明内存单元的长度,X在汇编指令中可以为word或者byte
- word ptr
- byte ptr
- word ptr
-
其他方法
- 有些指令默认了访问的单元是字单元还是字节单元、
- 例如:push 因为push只进行字操作 sp = sp - 2
8.6、寻址方式的综合应用
通过例子来进一步的探讨各种寻址的作用
mov ax,seg
mov ds,ax
mov bx,60h ;确定记录地址ds:bx
mov word ptr [bx+0ch],38 ;排名字段改为38
add word ptr [bx+0eh],70 ;收入字段增加70
mov si,0 ;用si来定位产品字符串中的字符
mov byte ptr [bx+10h+si],'v'
inc si
mov byte ptr [bx+10h+si],'A'
inc si
mov byte ptr [bx+10h+si],'x'
我们可以看出,8086CPU提供的如[bx+si+idata]的寻址方法为结构化的处理提供了方便
从上面可以看到,一个结构化的数据包含了多个数据项,而数据项的类型又不相同,有的是字型数据,有的是字节型数据,有的是数组(字符串)。
一般来说,我们用[bx+si+idata]的方式来访问结构体中的数据,用bx定位整个结构体,用idata定位结构体中的某一个数据项,用si定位数组项中的每个元素。为此,汇编语言提供了更为贴切的书写方式,如:[bx].idata、[bx].idata[si]。
8.7、div指令
div是除法指令,使用div做除法的时候:
- 除数:8位或者16位,在寄存器的内存单元中
- 被除数:默认放在AX或者是DX和AX中
除数和被除数的关系
除数 被除数
8位 16位(AX)
16位 32位(DX和AX)
结果存放:
运算 8位 16位
商 AL AX
余数 AH DX
div指令格式
-
div reg(寄存器)
-
div 内存单元
div指令的示例
-
div byte ptr ds:[0] 含义如下
- (al) = (ax)/((ds)*16+0)的商
- (ah) = (ax)/((ds)*16+0)的余数
-
div word ptr ds:[0] 含义如下
- (ax) = [(dx)*10000H + (ax)]/ ((ds) * 16+0)的商
- (dx) = [(dx)*10000H + (ax)] / ((ds) *16+0)的余数
-
div byte ptr [bx+si+8]
- (al)=(ax)/((ds) * 16 +(bx)+(si)+8)的商
- (ah)=(ax)/((ds) * 16 +(bx)+(si)+8)的余数
-
div word ptr [bx+si+8 ]
- (ax)=[ (dx) * 10000H+(ax) ] / ( (ds)*16+(bx)+(si)+8)的商
- (dx)= [ (dx) * 10000H+(ax)] / ((ds)*16+(bx)+(si)+8)的余数
编程实现除法指令计算 100001/100
分析:被除数100001的值大于了65535,所以不能用ax存放,只能用ax和dx联合起来存放
除数100小于255,可以在一个8位的寄存器中存放,但是由于被除数是32位则此时除数应该为16位,所以用一个16位的寄存器存放除数100
因为要分别将dx和ax赋100001的高16位和低16位,所以应该先将100001表示为16进制形式:186A1H
mov bx,1
mov ax,86A1H
mov bx,100
div bx
编程实现除法指令计算1001/100
分析:被除数1001小于65535,因此可以用ax进行存放,除数可以用8位的寄存器存放
mov ax,1001
mov bl,100
div bl
8.8、伪指令dd
之前学过的db定义的字节型数据,dw定义的字型数据
dd是用来定义dword(double word双字)型数据的
示例:datasg segment
db 1
dw 1
dd 1
datasg ends
在datasg段中定义的三个数据:
第一个数据:01H 在datasg:0处,占一个字节空间
第二个数据:0001H 在datasg:1处,占一个字型空间
第三个数据:00000001H 在datasg:3处,占一个双字型空间
问题8.1:用div计算 data段中第一个数据除以第二个数据后的结果,商存在第三个数据的存储单元中。
data segment
dd 100001
dw 100
dw 0
data ends
分析:data 段中的第一个数据是被除数,为 dword(双字)型,32位,所以在做除法之前,用dx 和 ax存储。应将data:0字单元中的低16位存储在ax 中,data:2字单元中的高16位存储在dx中。程序如下。
mov ax,data
mov ds,ax
mov ax,ds:[0] ;ds:0字单元中的低16位存储在ax中
mov dx,ds:[2] ;ds :2字单元中的高16位存储在dx中
div word ptr ds:[4] ;用dx :ax中的32位数据除以ds :4字单元中的数据
mov ds:[6],ax ;将商存储在ds:6字单元中
8.9、dup
dup是一个操作符,由编译语言中同db,dw,dd等一样,也是由编译器进行识别处理的符号
它是和db,dw,dd等数据定义的伪指令配合使用,用来进行数据的重复
dup示例
-
db 3 dup(0) 定义了三个字节,它们的值都是0 相当于db 0,0,0
-
db 3 dup(0,1,2) 定义了九个字节,它们是0,1,2,0,1,2,0,1,2
-
db 3 dup(‘abc’,'ABC) 定义了18个字节 它们是a,b,c,A,B,C,a,b,c,A,B,C,a,b,c,A,B,C
dup的使用格式
- db 重复的次数 dup(重复的字节型数据)
- dw 重复的次数 dup(重复的字型数据)
- dd 重复的次数 dup(重复的双字型数据)
dup是一个非常有用的操作符
例如定义一个容量为200个字节的栈段时,不使用dup
如果使用dup则为:
stack segment
db 200 dup(0)
stack ends