汇编语言之数据处理的2个基本问题

1、bx、si、di和bp

Bx、si和di这3个寄存器我们已经学过了,现在进行一下总结,并学一下bp。

1:在8086CPU中,只有这4个寄存器可以用在[…]中来进行内存单元的寻址。比如,下面的指令都是正确

的:

Mov ax, [bx]

Mov ax, [bx+si]

Mov ax, [bx+di]

Mov ax, [bp]

Mov ax, [bp+si]

Mov ax, [bp+di]

而下面的指令是错误的:

Mov ax, [ax]

Mov ax, [cx]

Mov ax, [dx]

Mov ax, [ds]

2:在[…]中,这4个寄存器可以单个出现,或只能以4种组合出现:bx和si、bx和di、bp和si、bp和di。

比如,下面的指令是正确的:

Mov ax, [bx]

Mov ax, [si]

Mov ax, [di]

Mov ax, [bp]

Mov ax, [bx+si]

Mov ax, [bx+di]

Mov ax, [bp+si]

Mov ax, [bp+di]

Mov ax, [bx+si+idata]

Mov ax, [bx+di+idata]

Mov ax, [bp+si+idata]

Mov ax, [bp+di+idata]

而下面的指令是错误的:

Mov ax, [bx+bp]

Mov ax, [si+di]

 
我们可以在访问内存单元的指令中显式地给出内存单元的段地址所在的段寄存器。

比如:mov ax, SS:[bx]    ;段地址在SS中。

      Mov ax, DS:[bp]    ;段地址在DS中。

      Mov ax, CS:[bp]    ;段地址在CS中。

      Mov ax, ES:[bp]    ;段地址在ES中。

在上面的指令:mov ax, ES:[bp] 中,我们接触到了一个新的段寄存器ES,ES叫附加段寄存器,它的功能与

DS基本相同。

如果在[…]中使用寄存器bp,而指令中没有显式地给出段地址,段地址就默认在SS中。比如,下面的指令:

Mov ax, [bp+200] 内存单元[bp+200]的段地址就在SS中。

BP被称作基址指针寄存器,它可以作SP使用,除了BP可以作为间接寻址寄存器而SP不能外,其余功能基

本相同。
 

事实上,通用寄存器除了ax、bx、cx、dx这4个外,还包括sp、bp、si、di这4个16位寄存器,以及ah、

al、bh、bl、ch、cl、dh、dl这8个8位寄存器,通用寄存器一共有以上这16个。

2、机器指令处理的数据在什么地方

绝大部分机器指令都是进行数据处理的指令,处理大致可分为3类:读取、写入、运算。在机器指令这一层来

讲,并不关心数据的值是多少,而关心指令执行前一刻,它将要处理的数据所在的位置。指令在执行前,所要处理

的数据可以在3个地方:CPU内部、内存、端口,比如下图所列的指令:

3、汇编语言中的数据位置的表达

在汇编语言中如何表达数据位置?汇编语言中用3个概念来表达数据的位置,即立即数、寄存器、地址(偏移

地址和段地址)。

1. 立即数(idata)

对于直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中),在汇编语言中称为:立即数(idata)。

例:mov ax, 136aH    ;指令要处理的数据就是立即数136aH。

Add ax, 2000H    ;指令要处理的数据就是立即数2000H。

Sub ax, a2c7H    ;指令要处理的数据就是立即数a2c7H。

2. 寄存器

指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。

例:mov ax, bx    ;指令要处理的数据在bx中。

Mov ds, ax    ;指令要处理的数据在ax中。

Push bx    ;指令要处理的数据在bx中。

Mov DS:[123a], bx    ;指令要处理的数据在bx中。

3. 段地址和偏移地址

指令要处理的数据在内存中,在汇编指令中可用[…]的格式给出偏移地址,段地址在某个段寄存器中。比如以下

的指令:

Mov ax, [107a]

Mov ax, [di]

Mov ax, [bx+8]

Mov ax, [bx+si]

Mov ax, [bx+si+8]

指令要处理的数据偏移地址在[…]中,段地址默认在DS中。

下面的指令:

Mov ax, [bp]

Mov ax, [bp+8]

Mov ax, [bp+si]

Mov ax, [bp+si+8]

指令要处理的数据偏移地址在[…]中,段地址默认在SS中。

存放段地址的寄存器也可以是显性给出的,比如以下指令:

mov ax, DS:[bp]    ;指令要处理的数据,段地址在DS中。

Mov ax, ES:[bx]    ;指令要处理的数据,段地址在ES中。

Mov ax, SS:[bx+si]    ;指令要处理的数据,段地址在SS中。

Mov ax, CS:[bx+si+8]    ;指令要处理的数据,段地址在CS中。
 

4、寻址方式


对寻址方式进行一下总结,见下表:表中EA=偏移地址,SA=段地址,寄存器加上一个小括号,表示这个

寄存器中的数值,比如第二条含义:EA=(bx);SA=(ds),(bx)就表示bx中的数值,(ds)就表示ds中的数

值。

5、指令要处理的数据有多长

8086CPU的指令,可以处理两种尺寸的数据:byte和word。所以在机器指令中要指明,指令进行的是字操

作还是字节操作,对于这个问题,汇编语言中用以下方式处理。

1. 通过寄存器名指明要处理的数据的尺寸。

例如,下面的指令中,寄存器指明了指令进行的是字操作,因为这些寄存器是16位的。

Mov ax, 123H

Mov bx, DS:[210a]

Add ax, 1000H

Sub bx, 2ffH

下面的指令中,寄存器指明了指令进行的是字节操作,因为这些寄存器是8位的。

Mov al, 12H

Mov bl, DS:[210a]

Add al, 10H

Sub bl, 2fH

2. 在没有寄存器名存在的情况下,用操作符word prt或byte prt指明内存单元的长度,前者为字单元,后者

为字节单元。

例如,下面的指令中,用word ptr指明了指令访问的内存单元是一个字单元。

Mov word ptr DS:[a017], 28H

Add word ptr [bx], 78H

下面的指令中,用byte prt指明了指令访问的内存单元是一个字节单元。

Mov byte ptr DS:[1a7], 1aH

Add byte ptr [bx], 62H

在没有寄存器参与的内存单元访问指令中,用word ptr或byte ptr显性地指明所要访问的内存单元的长度是

很必要的,否则,CPU无法得知所要访问的单元是字单元还是字节单元,从而造成出错。

3. 其它方法。有些指令默认了访问的是字单元还是字节单元,比如:push [123a]和pop[123c]就不用指明访

问的是字单元还是字节单元,因为push和pop指令只进行字操作。

6、mul指令

Mul为乘法指令,使用mul做乘法的时候,注意以下两点:

1. 两个相乘的数:这两个相乘的数,要么都是8位,要么都是16位,如果是8位,一个默认放在al中,另一

个放在8位寄存器或内存字节单元中;如果是16位,一个默认放在ax中,另一个放在16位寄存器或内存字单元

中。

2.结果:如果是8位乘法,结果默认放在ax中,如果是16位乘法,结果高位默认在dx中存放,低位在ax

中存放。

指令格式如下:

Mul 通用寄存器

Mul 内存单元

内存单元可以用不同的寻址方式给出,比如:

Mul byte ptr DS:[7102]    ;8位乘法。

Mul word ptr [bx+si+8]    ;16位乘法。

例1:计算100×10。

100和10都小于255,可以做8位乘法,代码如下:

Mov al, 100

Mov bl, 10

Mul bl

结果:ax=al×bl=100×10=1000(3E8H)

例2:计算100×10000。

100小于255,可10000大于255,所以必须做16位乘法,代码如下:

Mov ax, 100

Mov bx, 10000

Mul bx

结果:ax×bx=100×10000=1000000(F4240H)

Ax=4240H  dx=FH

7、div指令

Div是除法指令,使用div做除法的时候,应注意以下问题:

1. 除数:有8位和16位两种,在一个寄存器或内存单元中。

2. 被除数:如果除数为8位,被除数则为16位,默认放在ax中;如果除数为16位,被除数则为32位,在

Dx和ax中存放,dx存放高16位,ax存放低16位。

3. 结果:如果除数为8位,则al存储结果的商,ah存储结果的余数;如果除数为16位,则ax存储结果的

商,dx存储结果的余数。

指令格式如下:

Div 通用寄存器

Div 内存单元

内存单元可以用不同的寻址方式给出,比如:

Div byte ptr DS:[21a5]    ;除数为8位的除法。

Div word ptr [bx+si+8]    ;除数为16位的除法。

例1:计算100001÷100。

被除数100001为32位,转化成16进制为186a1H,低16位值86a1H放在ax中,高16位值1H放在

Dx中,除数100转化为16进制64H后,放在一个16位寄存器中,代码如下:

Mov dx, 1H

Mov ax, 86a1H

Mov bx, 64H

Div bx

结果:(dx×10000H+ax)÷bx=186a1H÷64H=3E8H余1。

Ax=3e8H(1000)  dx=1H

例2.计算1001÷100。

被除数1001可用ax存放,除数100可用8位寄存器存放,代码如下:

Mov ax, 1001

Mov bl, 100

Div bl

结果:ax÷bl=1001÷100=10余1。

Al=10  ah=1 

 

 






作者:chen.yu
深信服三年半工作经验,目前就职游戏厂商,希望能和大家交流和学习,
微信公众号:编程入门到秃头 或扫描下面二维码
零基础入门进阶人工智能(链接)