需要注意的几点:
1.调用子程序的过程是:首先,通过CALL指令,将当前指令的下一条指令的偏移地址IP入栈(也就是PUSH IP),这个IP就叫做断点,然后转到子程序,执行子程序,最后通过RET指令返回断点(POP IP)。
2.在调试出程序前,出现了很多错误,不过都一一解决,例如个人认为其中一个比较难以解决的问题:
首先,我们看到,这条语句是调用主程序main,因此,先保存断点也就是下一条语句的IP,因此此时堆栈中的情况如下:
然后,比如说我们输入了1,那么,分支程序的跳转将是这样:
好了,又到了调用子程序的时候了,所以,此时堆栈情况看下:
进入子程序:
我们看到有入栈操作,所以此时堆栈情况:
接着我们阅读程序,发现在标号outpu11前面都没有入栈出栈操作,而且只有在敲入回车键时,程序才会转到这里,而在本程序中,键入回车是表示当前录入结束,并且录入的数的每一位分别在x+1,x+2,x+3单元中,而标号outpu1下的程序是对键入的数进行处理,检查是否合法,如果输入的数合法,那么就将该数存入字节数组buf中,然而,这个时候就是重点了,由于在前面,我们在键入数时用到了bx寄存器,而这里要往数组中存放数据,那么,我们就要用到bx当做指针了。在这时,因为bx之前已经在录入数时被改变,所以我们要将刚刚保存在堆栈里的bx再次出栈,然后用其做指针,把输入的数存进去(每次处理完毕的数最后都存在了al中,是因为源操作数和目标操作数不能同时为存储器操作数,所以这里用al过渡一下)。
这里着重看这三句,假使每次输入的数都是合法的,并且假设输入了3次(见左图),那么在第三次录入完毕时(见右图)
如果这时我们输入了一个'$',程序跳到outpu12去执行,好了,这个时候问题就出来了,首先声明,outpu12下的程序就是比较输出了,然而我们此时却还有一个数没有出栈,那么会造成怎样的影响呢,且看这个子程序的最后三句:
前面两个各调用了子程序ooout和clearall,这是没有问题的,首先声明,在这两个子程序中没有入栈出栈等影响堆栈的操作。好了,现在要执行RET指令返回主程序了,那么,此时弹出的IP是什么呢,显然,并不是"ld"这条语句的IP,这会造成非常严重的问题。因此,个人不建议在调用子程序时使用入栈出栈的方法保存数据,如果非要用这样的方法,那么请一定不要像我一样,在还未对当前堆栈内容进行考虑的情况下就返回主程序。建议使用自定义的存储单元对数据进行保存。
代码如下:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;主程序功能介绍:1.求输入数<-128~127>中的最大值
; 2.对输入的数<-128~127>进行输出,并且对其进行正序和逆序遍历
;
;子程序功能介绍:1.子程序ooout:输出一个数
; 2.子程序clearall:对数组进行清0,对寄存器进行复位等重置操作
; 3.子程序oumax:求输入数的最大值
; 4.子程序sortinput:对输入的数进行输出,并且对其进行正序和逆序遍历
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include 一套工具.mac
data segment
show db "Please Select Operations:",13,10,"1.GetMax..",13,10,"2.SortNumbers..$"
show0 db "Please Input numbers<input ""$"
show1 db """ to output>:$"
iit1 db "The $"
iit2 db " number is:$"
buf db 20 dup(?)
x db ?,?,?,? ;x[0]用来存负号
w db ? ;用于显示提示信息
min db ?
boundary db "128$"
display0 db "Max:$"
display1 db "Input Numbers:$"
display2 db "Sort Numbers:$"
display3 db "ReSort Numbers:$"
error1 db "Input error!<you can check whether it is between -128~127>",13,10,"Please Input again:$"
error12 db "Input error!$"
sort db 20 dup(?)
temp db ?
temp01 dw ?
n dw ?,?
n1 dw ?
data ends
stack segment
stack ends
code segment
assume ds:data,cs:code,ss:stack
start:
mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
call main
jmp exit
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;main主程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
main proc
sss2:
oustring show
ld
mov ah,1
int 21h
cmp al,31h
jz it1
cmp al,32h
jz it2
cmp al,27
jz eout
error3:
ld
oustring error12
ld
jmp sss2
it2:
call sortinput
jmp sss2
it1:
call oumax
ld
jmp sss2
eout:
ret
main endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sortinput子程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sortinput proc
mov bx,0
push bx
;显示提示输入信息
ld
oustring show0
output '$'
oustring show1
ld
mov bx,1
inpu1: ;显示提示输入信息
oustring iit1
inc w
cmp w,9
jg www
mov dl,w
add dl,30h
mov ah,2
int 21h
oustring iit2
set1: ;输入
input
cmp al,1bh ;ESC退出
jz error2
cmp al,13 ;回车
jz outpu1
cmp al,36 ;$
jz outpu2
cmp al,'-'
jz minus
;判断是否在0-9
cmp al,30h
jl error0
cmp al,39h
jg error0
cmp bx,4
jg error0
sub al,30h
mov x[bx],al ;输入的字符合法,从x[1]开始存
inc bx
jmp set1
error2:
ret
minus:
cmp x[0],0
jnz error0 ;负号已存在则输出错误信息
mov x[0],al ;把负号存入x[0]中
jmp set1
outpu1:
cmp bx,1
jz error0
cmp x[0],'-'
jz negativedealwith
cmp bx,2
jz onedigit
cmp bx,3
jz twodigit
mov al,x+1
mov cl,100
imul cl
mov bl,al
mov al,x+2
mov cl,10
imul cl
add al,x+3
mov bh,0
cbw
add ax,bx
cmp ax,127
jg error0
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear
onedigit:
pop bx
mov al,x+1
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear
twodigit:
mov al,x+1
mov cl,10
imul cl
add al,x+2
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear
negativedealwith:
cmp bx,2
jz onebit
cmp bx,3
jz twobit
mov al,x+1
mov cl,100
imul cl
mov bl,al
mov al,x+2
mov cl,10
imul cl
add al,x+3
mov bh,0
cbw
neg ax
neg bx
add ax,bx
cmp ax,-128
jl error0
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear
onebit:
mov al,x+1
neg al
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear
twobit:
mov al,x+1
mov cl,10
imul cl
add al,x+2
neg al
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear
clear:
;清0操作
mov bx,0
mov cx,4
re2:
mov x[bx],0
inc bx
loop re2
mov bx,1
ld
jmp inpu1
error0: ;输入错误
ld
oustring error1
;关键的一步,清0操作
mov bx,0
mov cx,4
re1:
mov x[bx],0
inc bx
loop re1
mov bx,1
jmp set1
www: ;显示提示输入信息
mov al,w
cbw
mov cl,10
idiv cl
mov cl,ah
add al,30h
output al
add cl,30h
output cl
oustring iit2
jmp set1
outpu2:
cmp n,0
je error0
pop ax
mov n+2,ax
ld
oustring display1
ld
mov cx,n
mov bx,0
mov temp01,bx
inn:
push cx
mov al,buf[bx]
call ooout
pop cx
output 32
inc bx
loop inn
ld
oustring display2
ld
mov cx,n
osort:
dec cx
cmp cx,1
jl outsort
mov n1,cx
mov bx,0
mov al,buf[bx]
mov min,al
set2:
mov al,buf[bx+1]
cmp min,al
jg exchange
inc bx
loop set2
jmp savemin
exchange:
mov min,al
inc bx
loop set2
savemin:
mov bx,temp01
mov al,min
mov sort[bx],al
inc bx
cmp bx,n
jz outsort
mov temp01,bx
;找到最小数并把最小的数放入最后一个存储单元
mov bx,0
cmin:
mov al,buf[bx]
cmp al,min
jz deletem
inc bx
jmp cmin
deletem: ;找到了最小数下标为bx
mov temp,al
mov cx,n+2
dec cx
cmp bx,cx
jz sss1
sub cx,bx
set3:
mov al,buf[bx+1]
mov buf[bx],al
inc bx
loop set3
mov al,temp
mov buf[bx],al
sss1:
dec n+2
mov cx,n1
jmp osort
;输出排序后的
outsort:
mov bx,n
dec bx
mov al,buf[0]
mov sort[bx],al
mov cx,n
mov bx,0
set4:
push cx
mov al,sort[bx]
call ooout
pop cx
inc bx
output 32
loop set4
ld
oustring display3
ld
mov cx,n
mov bx,0
set5:
push cx
mov al,buf[bx]
call ooout
pop cx
inc bx
output 32
loop set5
ld
call clearall
ret
sortinput endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oumax子程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
oumax proc
mov bx,0
push bx
mov bx,1
;显示提示输入信息
ld
oustring show0
output '$'
oustring show1
ld
inpu11: ;显示提示输入信息
oustring iit1
inc w
cmp w,9
jg www1
mov dl,w
add dl,30h
mov ah,2
int 21h
oustring iit2
set11: ;输入
input
cmp al,1bh ;ESC退出
jz error112
cmp al,13 ;回车
jz outpu11
cmp al,36 ;'$'
jz outpu12
cmp al,'-'
jz minus1
;判断是否在0-9
cmp al,30h
jl error10
cmp al,39h
jg error10
cmp bx,4
jg error10
sub al,30h
mov x[bx],al ;输入的字符合法,从x[1]开始存
inc bx
jmp set11
error112:
ret
minus1:
cmp x[0],0
jnz error10 ;负号已存在则输出错误信息
mov x[0],al ;把负号存入x[0]中
jmp set11
outpu11:
cmp bx,1
jz error10
cmp x[0],'-'
jz negativedealwith1
cmp bx,2
jz onedigit1
cmp bx,3
jz twodigit1
mov al,x+1
mov cl,100
imul cl
mov bl,al
mov al,x+2
mov cl,10
imul cl
add al,x+3
mov bh,0
cbw
add ax,bx
cmp ax,127
jg error10
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear1
onedigit1:
pop bx
mov al,x+1
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear1
twodigit1:
mov al,x+1
mov cl,10
imul cl
add al,x+2
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear1
negativedealwith1:
cmp bx,2
jz onebit1
cmp bx,3
jz twobit1
mov al,x+1
mov cl,100
imul cl
mov bl,al
mov al,x+2
mov cl,10
imul cl
add al,x+3
mov bh,0
cbw
neg ax
neg bx
add ax,bx
cmp ax,-128
jl error10
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear1
onebit1:
mov al,x+1
neg al
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear1
twobit1:
mov al,x+1
mov cl,10
imul cl
add al,x+2
neg al
pop bx
mov buf[bx],al
inc bx
inc n
push bx
;清0
jmp clear1
clear1:
;清0操作
mov bx,0
mov cx,4
re12:
mov x[bx],0
inc bx
loop re12
mov bx,1
ld
jmp inpu11
error10: ;输入错误
ld
oustring error1
;关键的一步,清0操作
mov bx,0
mov cx,4
re11:
mov x[bx],0
inc bx
loop re11
mov bx,1
jmp set11
www1: ;显示提示输入信息
mov al,w
cbw
mov cl,10
idiv cl
mov cl,ah
add al,30h
output al
add cl,30h
output cl
oustring iit2
jmp set11
outpu12:
cmp n,0
jz error10
ld
oustring display0
pop cx
dec cx
mov bx,0
mov al,buf[bx]
set12:
cmp al,buf[bx+1]
jl exchange1
inc bx
loop set12
jmp outpu13
exchange1:
mov al,buf[bx+1]
inc bx
loop set12
outpu13:
call ooout
call clearall
ret
oumax endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ooout子程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ooout proc
outpu3:
mov min,al
cmp min,0
jl minusout
outpu4:
cmp min,10
jl oneout1
cmp min,100
jl twoout1
mov al,min
cbw
mov cl,100
idiv cl
mov cl,ah
add al,30h
output al
mov al,cl
cbw
mov cl,10
idiv cl
mov cl,ah
add al,30h
output al
add cl,30h
output cl
ret
oneout1:
add min,30h
output min
ret
twoout1:
mov al,min
cbw
mov cl,10
idiv cl
mov cl,ah
mov dl,al
add dl,30h
mov ah,2
int 21h
add cl,30h
output cl
ret
minusout:
output '-'
cmp min,-128
jz outpu5
neg min
jmp outpu4
outpu5:
oustring boundary
ret
ooout endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;clearall子程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
clearall proc
mov bx,0
mov cx,n
cl1:
mov buf[bx],0
mov sort[bx],0
inc bx
loop cl1
mov n,0
mov n+2,0
mov w,0
ret
clearall endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
exit:
mov ah,4ch
int 21h
code ends
end start
运行结果如下: