汇编:自定义一个简单的子程序,就暴露出比较严重并且容易忽略掉的问题,个人不建议在调用子程序时使用入栈出栈的方法保存数据

需要注意的几点:

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
 
 

运行结果如下:


猜你喜欢

转载自blog.csdn.net/baidu_38760069/article/details/80537044