更灵活的定位内存地址的方法
前面,我们用[0]、[bx]的方法,在访问内存的指令中,定位内存单元的地址。本章将用更灵活的方式来定位内存地址。
7.1 and和or指令
(1)and指令:逻辑与指令,按位进行与运算。例如:
mov al,01100011B
and al,00111011B
;执行后:al = 00100011B
(2)or指令:逻辑或指令,按位进行或运算。例如:
mov al,01100011B
or al,00111011B
;执行后:al = 01111011B
7.2 关于ASCII码
略
7.3 以字符形式给出的数据
用‘……’的方式指明数据是以字符的形式给出,编译器将它们转化为相应的ASCII码。如下:
assume cs:code,ds:data
data segment
db 'unIX' ;相当于 db 75H,6EH,49H,58H
db 'foRK' ;同理,下面的也是
data ends
code segment
start: mov al,'a'
mov bl,'b'
mov ax,4c00h
int 21h
code ends
end start
debug运行查看是否:
先用r命令分析一下data段的地址,因“ds=075A”,所以程序从076AH段开始,data段又是程序中的第一个段,它就在程序的起始处,所以它的段地址为0B3DH。
7.4 大小写转换的问题
考虑这样一个问题,在codesg中填写代码,将datasg中的第一个字符串转化为大写,第二个字符串转化为小写。
assume cs:codesg,ds:datasg
datasg segment
db 'BaSic'
db 'iNfOrMaTiOn'
datasg ends
codesg segment
start:
codesg ends
ends start
主要问题是怎么判断一个字母是大写还是小写?不过我们好像没有学过如何判断一个字母大小写的指令。所以该怎么办呢?
我们观察发现,ASCII码的二进制形式有一个规律!如下:
因此,我们可以用刚刚学过的and和or来做这个实验!这里指出方法:
变成大写:只要and al,11011111B
变成小写:只要or al,00100000B
7.5 [bx+idata]
指令mov ax,[bx+200]中的[bx+200]数学化的描述:(ax) = ((ds)*16+(bx)+200)。
问题 7.1
用Debug查看内存,结果如下:
2000:1000 BE 00 06 00 00 00 …
写出下面的程序执行后,ax、bx、cx中的内容。
mov ax,2000H ;ax=2000h
mov ds,ax ;ds=2000h
mov bx,1000H ;bx=1000h
mov ax,[bx] ;ax=00BEh
mov cx,[bx+1] ;cx=0600h
add cx,[bx+2] ;cx=0606h
7.6 用[bx+idata]的方式进行数组的处理
我们经常用的一个策略,这里直接略过吧!
7.7 SI和DI
si和di是8086CPU中和bx功能相近的寄存器,si和di不能够分成两个8位寄存器来使用。
下面3组实现了相同的功能:
;第一组
mov bx,0
mov ax,[bx]
mov ax,[bx+123]
;第二组
mov si,0
mov ax,[si]
mov ax,[si+123]
;第三组
mov di,0
mov ax,[di]
mov ax,[di+123]
问题 7.2
用si和di实现字符串’welcome to masm!’复制到它后面的数据区中。
assume cs:codesg,ds:datasg
datasg segment
db 'welcome to masm!'
db '................'
datasg ends
代码段(答案):
codesg segment
start:
mov ax,datasg
mov ds,ax
mov si,0
mov di,10h
mov cx,8
s:
mov ax,[si]
mov [di],ax
add si,2
add di,2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
问题 7.3
用更少的代码,实现问题7.2的程序
答案如下:
codesg segment
start:
mov ax,datasg
mov ds,ax
mov si,0
mov cx,8
s:
mov ax,[si]
mov [si+16],ax
add si,2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
7.8 [bx+si]和[bx+di]
指令mov ax,[bx+si]中的[bx+si]数学化的描述:(ax) = ((ds)*16+(bx)+(si))。
问题 7.4
用Debug查看内存,结果如下:
2000:1000 BE 00 06 00 00 00 …
写出下面的程序执行后,ax、bx、cx中的内容。
mov ax,2000h ;ax=2000h
mov ds,ax ;ds=2000h
mov bx,1000h ;bx=1000h
mov si,0 ;si=0h
mov ax,[bx+si] ;ax=00beh
inc si ;si=1h
mov cx,[bx+si] ;cx=0600h
inc si ;si=2h
mov di,si ;di=2h
add cx,[bx+di] ;cx=0606h
7.9 [bx+si+idata]和[bx+di+idata]
指令mov ax,[bx+si+idata]中的[bx+si+idata]数学化的描述:(ax) = ((ds)*16+(bx)+(si)+(idata))。
问题 7.5
用Debug查看内存,结果如下:
2000:1000 BE 00 06 00 6A 22 …
写出下面的程序执行后,ax、bx、cx中的内容。
mov ax,2000h ;ax=2000h
mov ds,ax ;ds=2000h
mov bx,1000h ;bx=1000h
mov si,0 ;si=0h
mov ax,[bx+2+si] ;ax=0006h
inc si ;si=1h
mov cx,[bx+2+si] ;cx=6a00h
inc si ;si=2h
mov di,si ;di=2h
mov bx,[bx+2+di] ;bx=226ah
7.10 不同的寻址方式的灵活应用
(1)[idata]用一个变量来表示地址,可用于直接定位一个内存单元。
(2)[bx]用一个变量来表示内存地址,可用于间接定位一个内存单元。
(3)[bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元。
(4)[bx+si]用两个变量表示地址。
(5)[bx+si+idata]用两个变量和一个常量表示地址。
问题 7.6
编程,将datasg段中每个单词的头一个字母改为大写字母。
assume cs:codesg,ds:datasg
datasg segment
db '1. file '
db '2. edit '
db '3. search '
db '4. view '
db '5. options '
db '6. help '
datasg segment
codesg segment
start:
;答案如下:
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,6
s:
mov al,[bx+3]
and al,11011111B
mov [bx+3],al
add bx,10h
loop s
mov ax,4c00h
int 21h
codesg ends
end start
问题 7.7
编程,将datasg段中每个单词改为大写字母。
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends
codesg segment
start:
;答案如下:
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s:
mov dx,cx
mov si,0
mov cx,3
s0:
mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s0
add bx,10h
mov cx,dx
loop s
mov ax,4c00h
int 21h
codesg ends
end start
其实,我们这里存cx应该需要用栈来存储。这是我们常用的方法,也是递归的本质。
如下:
assume cs:codesg,ss:stacksg,ds:datasg
;增加了栈空间
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends
codesg segment
start:
;答案如下:
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s:
push cx ;这里改变了
mov si,0
mov cx,3
s0:
mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s0
add bx,10h
pop cx ;这里也改变了
loop s
mov ax,4c00h
int 21h
codesg ends
end start
总结
这一章,我们主要学习了寻址方式:
- 寻址方式[bx(或 si、di)+idata]、[bx+si(或 di)]、[bx+si(或 di)+idata]的意义和应用。
- 二重循环问题的处理
- 栈的应用
- 大小写转化的方法
- and、or指令
实验6 实践课程中的程序
(1)将课程中所有讲解过的程序上机调试,用Debug跟踪其执行过程,并在过程中进一步理解所讲内容。
(2)编程,完成问题7.9中的程序。将下面datasg段的每个单词的前4个字母改为大写!
assume cs:codesg,ss:stacksg,ds:datasg
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
datasg segment
db '1. display '
db '2. brows '
db '3. replace '
db '4. modify '
datasg ends
codesg segment
start:
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s:
push cx
mov si,0
mov cx,4
s0:
mov al,[bx+si+3]
and al,11011111b
mov [bx+si+3],al
inc si
loop s0
add bx,16
pop cx
loop s
mov ax,4c00h
int 21h
codesg ends
end start
实验结果如下: