坑
1.存储器寻址时只能用BP,BX作为基址寄存器,DI,SI作为变址寄存器。
2.DOS系统2号中断功能(输出单字符)存在bug,会自动改变AL的值,故需进行入栈和出栈来对AX的内容进行保存。
3.用CALL指令进行递归时,PUSH一定要在CALL指令之前,否则栈顶最后存放的将是余数而不是地址,就无法递归了(具体见程序)。
4.循环条件自加时一定要注意位置,否则在条件判断时很容易就没法自加了……
5.length只在DUP返回重复数,其余时候都返回1
6.过程一定要有ret
代码样例:
1.十进制转2进制
;递归,缺点是不能自动去0,但是在做十进制输出时更优
change PROC
xor cx,cx
xor dx,dx
kkk:
mov ah,0 ;AH寄存器清0
mov bl,2
div bl
mov cl,al
mov dl,ah ;将余数送入DL
mov ch,ah
or cl,ch ;若余数和商都为0,则位递归停止条件
jz ppp ;返回 RET
push dx ;将DX压入栈,保存余数
call kkk ;递归,CALL存入断点
pop dx ;恢复余数
add dl,'0'
mov ah,2
int 21h
ppp:
ret
change ENDP
;参考了老师的思想,循环实现,每次输出商
change2 PROC
mov cx,7
kkk:
mov ah,0
push ax ;保存AX
push cx ;保存CX
mov al,1 ;AL赋初值1
mov bl,2
ppp:
mul bl ;AL乘2的CX次(依次从7-1,即结果为128-2)
loop ppp
mov bl,al ;将AL的值赋给BL
pop cx ;取出CX的值,用于大循环
pop ax
div bl
mov dl,al ;将商送入DL
mov al,ah ;将余数作为下一次的被除数
push ax
add dl,'0'
mov ah,2
int 21h
pop ax
loop kkk
push ax
mov dl,ah ;最后还应将最后的余数输出
add dl,'0'
mov ah,2
int 21h
pop ax
ret
change2 ENDP
2.字符串反转
DATAS SEGMENT
buf db'abcde$'
len dw 6
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov ax,len
mov bl,2
div bl
mov cl,al ;循环次数为len/2的商
mov ch,0
mov bp,offset buf
mov si,len
sub si,2 ;将变址寄存器SI指向len-2,(从0开始,且不反转$)
mov di,0 ;变址寄存器DI指向0开始
kkk:
mov al,[bp+di] ;变址寄存器寄存器不能减!
mov ah,[bp+si]
mov [bp+di],ah
mov [bp+si],al
inc di
dec si
loop kkk
mov dx,offset buf
mov ah,9
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START
3.求一数组中的偶数和
START:
MOV AX,DATAS
MOV ES,AX
mov bp,offset buf
mov di,0
mov cl,len
mov ch,0
mov dl,0
kkk:
mov al,ES:[bp+di]
mov ah,0
mov bl,2
div bl
test ah,0ffh ;判断余数是否为0
jnz ppp ;不为0的话跳转,不做加法
add dl,ES:[bp+di]
ppp:
inc di
loop kkk
mov bl,dl
call showbyte
MOV AH,4CH
INT 21H
CODES ENDS
END START
4.找出字符串(20个DB)中字母A的位置并显示其位置(不一定只有1个)
DATAS SEGMENT
buf db 'A',2,4,'A','A'
len db 5
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov bp,offset buf
mov di,0
mov cl,len
mov ch,0
kkk:
mov al,[bp+di]
cmp al,'A'
jnz ppp ;比较AL与'A'的大小关系,如果不相等则进入ppp,DI加1后进入下一次循环
push ax
mov dx,di
add dl,'0'
mov ah,2
int 21h
pop ax
ppp:
inc di
loop kkk
MOV AH,4CH
INT 21H
CODES ENDS
END START
5.建立一个过程,将数据段中定义的组合BCD码数据一一显示出来
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
showBCD PROC
push ax
mov al,bl
and al,0f0h ;取出高4位存入AL
mov cx,4
kkk: ;让其右移4位,高位自动补0
shr al,1
loop kkk
mov cl,10
mul cl ;AL乘10
mov dl,bl
and dl,0fh ;取出低4位
add al,dl ;高4位*10+低4位
mov bl,al
call showbyte
pop ax
ret
showBCD ENDP
START:
MOV AX,DATAS
MOV DS,AX
mov bp,offset buf
mov di,0
mov cx,2
ppp:
mov bl,[bp+di]
push cx ;将CX推入栈,防止过程中对CX的影响
call showBCD
call showspace
pop cx
inc di
loop ppp
MOV AH,4CH
INT 21H
CODES ENDS
END START
6.利用DOS系统功能调用,将键盘输入的小写字母转换成大写字母显示,如果输入的不是小写字母则输出#号(本质就是一个if——else的思想)
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov ah,8
int 21h
mov bl,'a'
mov bh,'z'
cmp al,bl
jl quit
cmp al,bh
jg quit
sub al,'a'-'A'
mov dl,al
jmp print ;AL的值装入后直接跳转到打印,防止进入quit
quit:
mov dl,'#'
print:
mov ah,2
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START
7.计算数据段中定义的两个压缩BCD码的和并且显示(加法完了过后加上DAA,显示也要用BCD码的显示格式)
START:
MOV AX,DATAS
MOV DS,AX
mov bp,offset buf
mov di,0
mov al,[bp+di]
inc di
mov cl,[bp+di]
add al,cl
daa
mov bl,al
mov cl,al
and cl,0fh
and bl,0f0h
push cx
mov cx,4
kkk:
shr bl,1
loop kkk
pop cx
mov al,bl
mov bl,10
mul bl
mov bl,al
add bl,cl
call showbyte
MOV AH,4CH
INT 21H
CODES ENDS
END START
8.将数据段中定义的字符串数组用MOV指令拷贝到附加段的异名数组中,拷贝完成后将附加段中的字母一一显示
方法1:直接利用MOVSB指令进行DS到ES的传输
DATAS SEGMENT
buf1 db 'abcde$'
len1 db 6
DATAS ENDS
EDATA SEGMENT
buf2 db 6 dup(?)
EDATA ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS,ES:EDATA
START:
MOV AX,DATAS
MOV DS,AX
MOV AX,EDATA
MOV ES,AX
mov si,offset buf1 ;将DS段的buf1的有效地址送入SI
mov di,offset buf2 ;将ES段的buf2的有效地址送入DI
mov cx,6 ;一共6个字节
cld ;正向送数据
rep movsb
mov dx,offset buf2 ;
mov ah,9
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START
方法2:利用循环传输
DATAS SEGMENT
buf1 db 'awede$'
len1 db 6
DATAS ENDS
EDATA SEGMENT
buf2 db 6 dup(?)
EDATA ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS,ES:EDATA
START:
MOV AX,DATAS
MOV DS,AX
MOV AX,EDATA
MOV ES,AX
mov bx,offset buf1
mov bp,offset buf2
mov si,0
mov cx,6
kkk: ;利用循环进行一位一位的传送
mov al,[bx+si]
mov [bp+si],al
inc si
loop kkk
mov dx,offset buf2
mov ah,9
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START
9.利用DOS系统功能调用,将从键盘输入的2个数字的余数显示出来
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov ah,1 ;从键盘输入第一个数
int 21h
mov bl,al
sub bl,'0' ;由于输入的是字符形式,需要减去'0'
mov ah,1 ;输入第二个数
int 21h
sub al,'0'
push ax
mov dl,10 ;输出一个回车
mov ah,2
int 21h
pop ax
xchg bl,al
mov ah,0
div bl
mov dl,ah
add dl,'0'
mov ah,2
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START
10.建立一个过程,将数据段中定义的字符串大小写反置显示在显示器上,即大写变成小写,小写变成大写再显示
DATAS SEGMENT
buf db 'aEcd$'
len dw 5
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
cov PROC
mov bp,offset buf
mov cx,2
mov di,0
mov si,3
kkk:
mov al,[bp+di] ;先把字符串的一位调入AL
mov ah,[bp+si]
cmp al,'a'
jge qqq ;如果大于等于a,则跳qqq
add al,'a'-'A' ;小写转大写
jmp www
qqq: ;大写转小写
sub al,'a'-'A'
www: ;进入下一次比较
cmp ah,'a'
jge eee
add ah,'a'-'A'
jmp rrr
eee:
sub ah,'a'-'A'
rrr:
mov [bp+di],ah
mov [bp+si],al
inc di
dec si
loop kkk
ret
cov ENDP
START:
MOV AX,DATAS
MOV DS,AX
call cov
mov dx,offset buf
mov ah,9
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START
11.寻找最后一个空格的位置
DATAS SEGMENT
buf db 'adf as de'
len dw 9
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov cx,len
mov bp,offset buf
mov di,0
kkk:
mov al,[bp+di]
cmp al,' '
jnz ppp
mov bx,di ;如果找到就覆盖
ppp:
inc di
loop kkk
mov dl,bl
add dl,'0'
mov ah,2
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START
12.一个字符串定义在DS内,一个定义在ES内,长度均为20。请找出第一个不同的字母的位置,并显示这两个字母
DATAS SEGMENT
buf1 db 'avdev'
DATAS ENDS
EDATA SEGMENT
buf2 db 'avdfe'
EDATA ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS,ES:EDATA
START:
MOV AX,DATAS
MOV DS,AX
MOV AX,EDATA
MOV ES,AX
mov bp,offset buf1
mov bx,offset buf2
mov di,0
mov cx,5
kkk:
push cx
mov al,[bp+di]
mov cl,es:[bp+di]
cmp al,cl
jnz ppp
inc di
ppp:
pop cx
loopnz kkk ;大坑,估计是编译器错了
mov dx,di
mov dh,0
add dl,'0'
mov ah,2
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START
DATAS SEGMENT
buf db 'AAABBBB'
len dw 7
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov cx,len
mov bp,offset buf
mov di,0
mov bx,0
kkk:
mov al,[bp+di]
cmp al,'A'
jnz ppp
inc bl
jmp qqq
ppp:
cmp al,'B'
jnz qqq
inc bh
qqq:
inc di
loop kkk
sub bh,bl
mov dl,bh
add dl,'0'
mov ah,2
int 21h
MOV AH,4CH
INT 21H
CODES ENDS
END START