[bx]和内存单元的描述
我们要完整地描述一个内存单元,需要两种信息:
(1)内存单元的地址;
(2)内存单元的长度(类型)。
我们用[0]表示一个内存单元时,0 表示单元的偏移地址,段地址默认在ds中,单元的长度(类型)可以由具体指令中的其他操作对象(比如说寄存器)指出。
[bx]同样也表示一个内存单元,它的偏移地址在bx中,比如下面的指令:
mov ax,[bx]
mov al,[bx]
为了描述上的简洁,在以后的文章中,使用一个描述性的符号 “() ”来表示一个寄存器或一个内存单元中的内容。这种方法主要为了叙述的方便,有点类似C语言的*运算的意味
我们看一下(X)的应用,比如:
(1)ax中的内容为0010H,我们可以这样来描述:(ax)=0010H;
(2)2000:1000 处的内容为0010H,我们可以这样来描述:(21000H)=0010H;
(3)对于mov ax,[2]的功能,我们可以这样来描述:(ax)=((ds)*16+2);
(4)对于mov [2],ax 的功能,我们可以这样来描述:((ds)*16+2)=(ax);
(5)对于 add ax,2 的功能,我们可以这样来描述:(ax)=(ax)+2;
(6)对于add ax,bx的功能,我们可以这样来描述:(ax)=(ax)+(bx);
(7)对于push ax的功能,我们可以这样来描述:
(sp) = (sp)-2
((ss)*16+(sp))=(ax)
注意:“()”中的元素可以有3种类型:寄存器名、段寄存器名、内存单元的物理地址
约定符号idata表示常量
比如:
mov ax,[idata]就代表mov ax,[1]、mov ax,[2]、mov ax,[3]等。
mov bx,idata就代表mov bx,l、mov bx,2、mov bx,3等。
mov ds,idata就代表mov ds,1、mov ds,2等,它们都是非法指令。
[BX]
我们看一看下面指令的功能:
mov ax,[bx]
功能:bx 中存放的数据作为一个偏移地址EA ,段地址SA 默认在ds 中,将SA:EA处的数据送入ax中。
即: (ax)=(ds *16 +(bx));
mov [bx],ax
功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将ax中的数据送入内存SA:EA处。
即:(ds *16 +(bx)) = (ax)。
来实践一下
mov ax,2000H mov ds,ax mov bx,1000H mov ax,[bx] inc bx inc bx mov [bx],ax inc bx inc bx mov [bx],ax inc bx mov [bx],al inc bx mov [bx],al
跟踪执行上面的代码:
首先执行-debug 2.exe
-r
AX=FFFF BX=0000 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=0000 NV UP EI NZ NA PO NC
076A:0000 B80020 MOV AX,2000
-t
AX=2000 BX=0000 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=0003 NV UP EI NZ NA PO NC
076A:0003 8ED8 MOV DS,AX
-t
AX=2000 BX=0000 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=0005 NV UP EI NZ NA PO NC
076A:0005 BB0010 MOV BX,1000
-t
AX=2000 BX=1000 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=0008 NV UP EI NZ NA PO NC
076A:0008 8B07 MOV AX,[BX] DS:1000=0000
这三条指令执行后
ds=2000H, bx=1000H;
-t
AX=0000 BX=1000 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=000A NV UP EI NZ NA PO NC
076A:000A 43 INC BX
说明:mov ax,[bx] 将内存2000:1000处的数据送入ax中,而DS:1000=0000,执行之后ax=0000H
-t
AX=0000 BX=1001 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=000B NV UP EI NZ NA PO NC
076A:000B 43 INC BX
-t
AX=0000 BX=1002 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=000C NV UP EI NZ NA PO NC
076A:000C 8907 MOV [BX],AX DS:1002=0000
连续执行inc bx inc bx,bx=1001H,bx=1002H
-t
AX=0000 BX=1004 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=000E NV UP EI NZ NA PO NC
076A:000E 43 INC BX
执行前,DS=2000H,BX=1002,执行MOV [BX],AX 即是将AX中的数据传到2000:1002处
接下来连续执行inc bx inc bx,bx=1003H,bx=1004H
-t
AX=0000 BX=1004 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=0010 NV UP EI NZ NA PO NC
076A:0010 8907 MOV [BX],AX DS:1004=0000
-t
AX=0000 BX=1004 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=0012 NV UP EI NZ NA PO NC
076A:0012 43 INC BX
执行前,DS=2000H,BX=1004,执行MOV [BX],AX 即是将AX中的数据传到2000:1004处
接下来连续执行inc bx,bx=1005H
-t
AX=0000 BX=1005 CX=001D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=2000 ES=075A SS=0769 CS=076A IP=0013 NV UP EI NZ NA PO NC
076A:0013 8807 MOV [BX],AL DS:1005=00
执行前,DS=2000H,BX=1005,执行MOV [BX],AX 即是将AL中的数据00传到2000:1005处
接下来连续执行inc bx,bx=1006H
后面的一点指令省略,原理都差不多
LOOP指令
指令的格式是:loop 标号,CPU 执行loop指令的时候,要进行两步操作:
① (cx)=(cx)-1;
② 判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行。
从上面的描述中,我们可以看到,cx中的值影响着loop指令的执行结果。
通常我们用loop指令来实现循环功能,cx 中存放循环次数。
任务1:编程计算2^12,结果存放在ax中。
分析:2∧12=2*2*2*2*2*2*2*2*2*2*2*2,若设(ax)=2,可计算:
(ax)= (ax)*2*2*2*2*2*2*2*2*2*2*2,最后(ax)中为2∧12的值。N*2可用N+N 实现。
assume cs:code code segment mov ax,2 mov cx,11 s: add ax,ax loop s mov ax,4c00h int 21h code ends end
程序分析:
(1)标号
在汇编语言中,标号代表一个地址,此程序中有一个标号s 。它实际上标识了一个地址,这个地址处有一条指令:add ax,ax。
(2)loop s
CPU 执行loop s的时候,要进行两步操作:
① (cx)=(cx)-1;
② 判断cx 中的值,不为0 则转至标号s 所标识的地址处执行(这里的指令是“add ax,ax),如果为零则执行下一条指令(下一条指令是mov ax,4c00h)。
(3)以下三条指令
mov cx,11
s: ddd ax,ax
loop s
执行loop s时,首先要将(cx)减1,然后若(cx)不为0,则向前转至s处执行add ax,ax。所以,我们可以利用cx来控制
add ax,ax的执行次数。
最后结果,ax=1000H
Comments