汇编语言基本概念(续6)

前面已经讲述了几种不同的寻址方式,这些寻址方式总结出来,就在于偏移地址的表示方式,偏移地址可以用常量也可以用变量,或者常量加上变量。这些方式都是可以接收的。另外8086CPU还设置了两个独立的寄存器SI,DI用来辅助BX,这两个寄存器都是16位的,因此,不能分成两个8位,同时书写方式也同前面所述的一样,可以灵活如下:

image

D:\Temp\NPP593~1.BIN\tmp>debug
-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=1400  ES=1400  SS=1400  CS=1400  IP=0100   NV UP EI PL NZ NA PO NC
1400:0100 0000          ADD    [BX+SI],AL                         DS:0000=CD
-d 2000:1000 BE 00 06 00 00 00
               ^ Error
-e 2000:1000 BE 00 06 00 00 00
-d 2000:1000
2000:1000  BE 00 06 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
2000:1010  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
2000:1020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
2000:1030  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
2000:1040  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
2000:1050  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
2000:1060  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
2000:1070  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
-a
1400:0100 mov ax,2000
1400:0103 mov ds,ax
1400:0105 mov bx,1000
1400:0108 mov si,0
1400:010B mov ax,[bx+si]
1400:010D inc si
1400:010E mov cx,[bx+si]
1400:0110 inc si
1400:0111 mov di,si
1400:0113 add cx,[bx+di]
1400:0115
-t

AX=2000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=1400  ES=1400  SS=1400  CS=1400  IP=0103   NV UP EI PL NZ NA PO NC
1400:0103 8ED8          MOV    DS,AX                             
-t

AX=2000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=0105   NV UP EI PL NZ NA PO NC
1400:0105 BB0010        MOV    BX,1000                           
-t

AX=2000  BX=1000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=0108   NV UP EI PL NZ NA PO NC
1400:0108 BE0000        MOV    SI,0000                           
-t

AX=2000  BX=1000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=010B   NV UP EI PL NZ NA PO NC
1400:010B 8B00          MOV    AX,[BX+SI]                         DS:1000=00BE
-t

AX=00BE  BX=1000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=010D   NV UP EI PL NZ NA PO NC
1400:010D 46            INC    SI                                
-t

AX=00BE  BX=1000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0001  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=010E   NV UP EI PL NZ NA PO NC
1400:010E 8B08          MOV    CX,[BX+SI]                         DS:1001=0600
-t

AX=00BE  BX=1000  CX=0600  DX=0000  SP=FFEE  BP=0000  SI=0001  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=0110   NV UP EI PL NZ NA PO NC
1400:0110 46            INC    SI                                
-t

AX=00BE  BX=1000  CX=0600  DX=0000  SP=FFEE  BP=0000  SI=0002  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=0111   NV UP EI PL NZ NA PO NC
1400:0111 89F7          MOV    DI,SI                             
-t

AX=00BE  BX=1000  CX=0600  DX=0000  SP=FFEE  BP=0000  SI=0002  DI=0002 
DS=2000  ES=1400  SS=1400  CS=1400  IP=0113   NV UP EI PL NZ NA PO NC
1400:0113 0309          ADD    CX,[BX+DI]                         DS:1002=0006
-t

AX=00BE  BX=1000  CX=0606  DX=0000  SP=FFEE  BP=0000  SI=0002  DI=0002 
DS=2000  ES=1400  SS=1400  CS=1400  IP=0115   NV UP EI PL NZ NA PE NC
1400:0115 0000          ADD    [BX+SI],AL                         DS:1002=06
-

总结一下前面所述的寻址方式如下:

【1】[idata]用一个常量来表示地址,可以直接定义一个内存单元,在MASM中用ds:[20],段前缀

【2】[bx]用一个变量来表示内存地址,可以间接定义一个内存单元,这里除了bx之外还可以si,di

【3】[bx+idata]用一个变量加上常量来表示内存地址,可在一个起始地址的基础上用变量间接定位一个内存单元,常用的写法有idata[bx]或[idata+bx]及[bx].idata

【4】[bx+si]用两个变量来表示地址

【5】[bx+si+idata]用两个变量加一个常量来表示地址,其写法同第三个一样也有三种。

D:\Temp\NPP593~1.BIN\tmp>debug
-e 2000:1000 BE 00 06 00 00
-a
1400:0100 mov ax,2000h
                     ^ Error
1400:0100 mov ax,2000
1400:0103 mov ds,ax
1400:0105 mov bx,1000
1400:0108 mov ax,[bx]
1400:010A mov cx,[bx+1]
1400:010D add cx,[bx+2]
1400:0110
-t

AX=2000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=1400  ES=1400  SS=1400  CS=1400  IP=0103   NV UP EI PL NZ NA PO NC
1400:0103 8ED8          MOV    DS,AX                             
-t

AX=2000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=0105   NV UP EI PL NZ NA PO NC
1400:0105 BB0010        MOV    BX,1000                           
-t

AX=2000  BX=1000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=0108   NV UP EI PL NZ NA PO NC
1400:0108 8B07          MOV    AX,[BX]                            DS:1000=00BE
-t

AX=00BE  BX=1000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=010A   NV UP EI PL NZ NA PO NC
1400:010A 8B4F01        MOV    CX,[BX+01]                         DS:1001=0600
-t

AX=00BE  BX=1000  CX=0600  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000 
DS=2000  ES=1400  SS=1400  CS=1400  IP=010D   NV UP EI PL NZ NA PO NC
1400:010D 034F02        ADD    CX,[BX+02]                         DS:1002=0006
-t

从汇编指令的角度来说,指令关心的是数据存储在什么位置,数据的长度是多长,至于说内容是不关注的,这些是业务去关注的。从描述的方便的角度,我们使用reg表示寄存器,通常包括16位的ax,bx,cx,dx,sp,bp,si,di以及8位的ah,al,bh,bl,ch,cl,dh,dl。用sreg表示段寄存器,通常包括ds,ss,cs,es。在8086CPU中用来表示内存偏移地址的只有bx,si,di和bp,这四个,注意,这当中还有一个两两互斥的关系,也就是bx与bp不能同时使用,si和di也是,但是bx+si,bx+di,bp+si,bp+di是可以的。默认的 bx的段寄存器是ds,默认的bp的段寄存器是ss。这一点要注意,它跟栈共用。机器指令通常大部分进行的是数据处理,所关注的数据通常在CPU内部寄存器、内存、端口等。

image

正如前面所讨论的,表示一个数据在内存或都寄存器中的方法,有如下三种:

【1】立即数(idata),直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中),mov ax,1

【2】寄存器,指令要处理的数据在寄存器中,mov ds,ax

【3】段地址和偏移地址, mov ax,[0] mov ax,[di]及mov ax,ds:[bp]

image

image

前面讲述的是数据的位置,也就是数据存放的地址,那么数据的长度怎么表示呢?通常寄存器默认是有规定的长度,如ax 16位,al 8 位。等如果没有指明寄存器情况下,使用word和byte +ptr来指明。mov word ptr ds:[0],1 或mov byte ptr ds:[0],1。其它像push默认就是字方式。到这里我们讲了数据段,数据在内存中的存放定义。我们使用dw,db来定义内存数据,但是我们想一想,如果有很多数据怎么办?而这些数据都是重复的,那么是不是要写死了。汇编中设计了一个由编译器识别的符号dup。dup可用定义重复的数据 db 3 dup (0) 定义了3个字节,相当于db 0,0,0 同理db 3 dup (0,1,2) 相当于定义了9个字节 db 0,1,2,0,1,2,0,1,2。提到数据的定义,这里还有一个符号也是需要提到的就是dd. dd是用来定义dworld(double word,双字型数据的),结合前面对数据的叙述,我们可以总结如下:

【1】db,dw,dd均可以用在数据段来定义内存中的数据

【2】dup用来定义数据段的重复数据。

前面我们讲了加法add指令,那么除法怎么做呢?汇编中有现成的除法指令div(division)。不过考虑到CPU只能做加法,对除法是通过加法进行模拟的。因此,除法需要注意位数。通常除数的大小有8位与16位两种,这只针对8086CPU架构来说。8080CPU对除法是进行加法模拟的,因此被除数必须有两块地方来存储商与余数。如果除数有8位,那么被除数肯定不小于8位,除得结果也可能是8位,因此余数就没地方放了,所以如果除数是8位,那么被除数一定是16位,同样,如果除数是16位,被除数是32位。

dive byte ptr ds:[0]

(al) = (ax)/((ds)*16+0) 的商

(ah)=(ax)/((ds)*16+0)的余数

div word ptr es:[0]

(ax) =[(ds)*10000H+(ax)]/((es)*16+0)的商

(dx)=[(ds)*10000H+(ax)]/((es)*16+0)的余数

image

image

从上面两道题的结果来看,进行除法运算时,需要先根据被除数大小,也就占用字节数,来按排除数占用的字节数,这个适用于除数可以用存储为8个字节也可以16个字节,如果除数只能16个字节,那就无法选择,只能32个字节的被除数。

你可能感兴趣的:(职场,休闲)