在这一章中,我们学习一些更灵活的定位内存地址的方法和相关的编程方法。
1、 两条指令and和or。
在汇编程序中,and 主要是置0, or主要是置1 。
例如:
将al的第6位设为0:and al, 10111111B
将al的第6位设为1:or al, 01000000B
2、 以字符的形式给出数据
在汇编程序中,用 “x”的方式指明数据是以字符的形式给出的,编译器将把它们转化为相对应的ASCII码。
如: MOV AX, 'A' 表示将‘A'的ASCII码 65赋值给AX。
3、大小写转换的问题
要改变一个字母的大小写,实际上就是要改变它所对应的ASCII 码。
小写字母的ASCII码值比大写字母的ASCII码值大20H (32)
大写 二进制 小写 二进制
A 01000001 a 01100001
B 01000010 b 01100010
C 01000011 c 01100011
D 01000100 d 01100100
可以看出,就ASCII码的二进制形式来看,除第5位(位数从0开始计算)外,
大写字母和小写字母的其他各位都一样。
大写字母ASCII码的第5位(位数从0开始计算)为0,小写字母的第5位为1。
也就是说一个字母,我们不管它原来是大写还是小写:
我们将它的第5位置0,它就必将变为大写字母;将它的第5 位置1,它就必将变为小写字母。
一道大小写转换的程序:
;大小写转换问题, BaSiC ,进行转换
ASSUME CS:CODESG, DS:DATASG
DATASG SEGMENT
DB 'BaSiC'
DATASG ENDS
CODESG SEGMENT
START:
MOV AX, DATASG
MOV DS, AX
MOV BX, 0
MOV CX, 5
S:
MOV AL, [BX]
OR AL, 00100000B ; 转换为小写
MOV [BX],AL
INC BX
LOOP S
MOV AX, 4C00H
INT 21H
CODESG ENDS
END START
4、新的表示 [bx+idata]
指令mov ax,[bx+200]也可以写成如下格式(常用):
mov ax,[200+bx]
mov ax,200[bx]
[bx+idata]的方式为高级语言实现数组提供了便利机制。
一道例题:
; 用[bx+idata]的方式进行数组的处理
; 将datasg 定义的第一个字符串转换为大写,第二个字符串转换为小写
ASSUME CS:CODESG, DS:DATASG
DATASG SEGMENT
DB 'BaSiC'
DB 'MinIX'
DATASG ENDS
CODESG SEGMENT
START:
MOV AX, DATASG
MOV DS, AX
MOV BX, 0
MOV CX, 5
S:
MOV AL, 0[BX]
AND AL, 0DFH ; 相当于 11011111B
MOV 0[BX], AL
MOV AL, 5[BX]
OR AL, 20H
MOV 5[BX], AL
INC BX
LOOP S
MOV AX, 4C00H
INT 21H
CODESG ENDS
END START
5、SI 和 DI
SI和DI是8086CPU中和bx功能相近的寄存器,但是SI和DI不能够分成两个8 位寄存器来使用
例题:
;用寄存器SI和DI实现将字符串‘welcome to masm!’复制到它后面的数据区中。
ASSUME CS:CODESG, DS:DATASG
DATASG SEGMENT
DB 'welcome to masm!'
DATASG ENDS
CODESG SEGMENT
START:
MOV AX, DATASG
MOV DS, AX
MOV SI,0
MOV DI,16
MOV CX, 16
S:
MOV AL,[SI]
MOV [DI], AL
INC DI
INC SI
LOOP S
MOV AX, 4C00H
INT 21H
CODESG ENDS
END START
我很不明白: 为什么最后一个'!'复制不了??????
6、 不同的寻址方式的灵活应用
如果我们比较一下前面用到的几种定位内存地址的方法(可称为寻址方式),就可以发现有以下几种方式:
(1)[iata] 用一个常量来表示地址,可用于直接定位一个内存单元;
(2)[bx]用一个变量来表示内存地址,可用于间接定位一个内存单元;
(3)[bx+idata] 用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元;
(4)[bx+si]用两个变量表示地址;
(5)[bx+si+idata] 用两个变量和一个常量表示地址。
7、书本几道例题
1); 将datasg段中的每个单词的头一个字符改为大写字母
ASSUME CS:CODESG, DS:DATASG
DATASG SEGMENT
DB '1. file '
DB '2. edit '
DB '3. search '
DB '4. view '
DB '5. option '
DB '6. help '
DATASG ENDS
CODESG SEGMENT
START:
MOV AX, DATASG
MOV DS, AX
MOV SI, 3
MOV CX, 6
S:
MOV AL, [SI]
AND AL, 0DFH
MOV [SI],AL
ADD SI, 16
LOOP S
MOV AX, 4C00H
INT 21H
CODESG ENDS
END START
2); 将 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 SI, 0
MOV DX, CX ; 临时存放cx的数值
MOV CX, 3
S1:
MOV AL, [BX+SI]
AND AL, 0DFH
MOV [BX+SI],AL
INC SI
LOOP S1
ADD BX, 16
MOV CX, DX
LOOP S
MOV AX, 4C00H
INT 21H
CODESG ENDS
END START
分析: 因为这里涉及到两重循环,而只有一个CX保存循环次数,那么意味着在进入内层循环的时候,
要先把CX暂时存放起来,内层循环执行完毕之后,再将它进行还原。本程序保存在DX中。
3)利用栈段存储暂时数据
; 将 datasg段中的每个单词改为大写字母,利用栈段
ASSUME CS:CODESG, DS:DATASG, SS:STACKSG
DATASG SEGMENT
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
DATASG ENDS
STACKSG SEGMENT
DW 0,0,0,0,0,0,0,0
STACKSG ENDS
CODESG SEGMENT
START:
MOV AX, DATASG
MOV DS, AX
MOV AX, STACKSG
MOV SS, AX
MOV SP, 16 ; 栈空
MOV BX, 0
MOV CX, 4
S:
MOV SI, 0
PUSH CX ;将CX进栈
MOV CX, 3
S1:
MOV AL, [BX+SI]
AND AL, 0DFH
MOV [BX+SI],AL
INC SI
LOOP S1
ADD BX, 16
POP CX ; 将CX 出栈
LOOP S
MOV AX, 4C00H
INT 21H
CODESG ENDS
END START
分析: 这里使用了栈来存储数据,这是一个比较好的做法,使用栈的时候,应该注意栈顶定位和栈顶越界问题。
4); 将datasg段中的每个单词的前四个字母改为大写字母
ASSUME CS:CODESG, DS:DATASG, SS:STACKSG
DATASG SEGMENT
DB '1. display '
DB '2. brows '
DB '3. replace '
DB '4. modify '
DATASG ENDS
STACKSG SEGMENT
dw 0,0,0,0,0,0,0,0
STACKSG ENDS
CODESG SEGMENT
START:
MOV AX, DATASG
MOV DS, AX
MOV AX, STACKSG
MOV SS, AX
MOV SP, 16 ; 栈为空
MOV BX, 0
MOV CX, 4
S:
MOV SI, 3
PUSH CX
MOV CX, 4
S1:
MOV AL, [BX+SI]
AND AL, 0DFH
MOV [BX+SI], AL
INC SI
LOOP S1
ADD BX, 16
POP CX
LOOP S
MOV AX, 4C00H
INT 21H
CODESG ENDS
END START
以上的程序可以看出:
暂存的数据,我们可以存放在寄存器中,也可以存放在内存中。
因为寄存器的数量有限,所以我们可以将暂存的数据放到内存单元中,
需要使用的时候,再从内存单元中恢复。这样的话,我们就需要开辟一段内存空间。
在需要暂存数据的时候,我们都应该使用栈,这样才是一个比较好的做法。
个人总结: 本章的重点主要有:
1)理解and和or指令如何使某一位置1或是0
2)理解大小写的转换问题(改变大小写,其实就是改变它所对应的ASCII 码)
3)弄明白书本的几道例题(必须掌握的知识)
4) 理解栈的作用(重点)