主题:关于子程序和栈的问题
学汇编几天了,在写子程序,可感觉自己写的很乱,完全没有风格之说,看书上说,如果子程序要用的相应的寄存器,那么要把该寄存器先压入栈以保存之前的数据,可我有个问题,如果一个寄存器被当做参数传入子程序,而子程序中又要用到寄存器该怎么办呢?我是把它压入栈等用的时候再弹出。。可。。。程序相当混乱。。希望有前辈指点下问题的所在
我把程序贴出来:
;程序功能是在屏幕指定行显示以下数据(其中包括人均值,要计算),其中有3个子程序,一个计算人均值,为了防止溢出而另外写的;一个是把数值转化成字符串的;另一个是在指定行显示字符串的。
assume cs:code, ds:data
data segment
dw 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983
dw 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992
dw 1993, 1994, 1995
dd 16, 22, 382, 1356, 2398, 8000, 16000, 24486, 50065, 97479, 140417, 197514
dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000
dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226
dw 11542, 14430, 15257, 17800
data ends
des segment
db 10 dup(0)
des ends
code segment
start:
mov ax, data
mov es, ax
mov ax, des
mov ds, ax
mov dh, 2
mov di, 0
mov si, 0
mov bp, 0
mov cx, 21
line:
push dx
mov ax, es:[di]
mov dx, 0
call dwtoc
mov al, 7
pop dx
inc dh
mov dl, 3
call show_str
push dx
mov ax, es:[2a+bp]
mov dx, es:[2c+bp]
call dwtoc
mov al, 7
pop dx
mov dl, 14
call show_str
push dx
mov ax, es:7e[di]
mov dx, 0
call dwtoc
mov al, 7
pop dx
mov dl, 28
call show_str
push dx
mov ax, es:02a[bp]
mov dx, es:02c[bp]
push cx
mov cx, es:7e[di]
call divdw
call dwtoc
pop cx
mov al, 7
pop dx
mov dl, 40
call show_str
inc dh
add di, 2
add bp, 4
loop line
ret
;;===================================================
;名称: show_str
;功能: 在指定位置,用指定颜色,显示一个用0结束的字符串
;参数: (dh)=行号(0~24)
; (dl)=列号(0~79)
; (al)=颜色
; ds:si指向字符串的首地址
;返回: 无
;;====================================================
show_str:
push es
push bx
push si
push ax
mov si, 0
mov al,0A0h
dec dh
mul dh
mov bx,ax
mov al,2
mul dl
sub ax,2
add bx,ax
mov ax,0B800h
mov es,ax
mov di,0
pop cx
mov al,cl
push cx
mov ch,0
s: mov cl,es:[si]
jcxz ok
mov es:[bx+di],cl
mov es:[bx+di+1],al
inc si
add di,2
jmp short s
ok: pop ax
pop si
pop bx
pop es
ret
;;===============================================
;名称: dwtoc
;功能: 将dword型数据转变为表示十进制数的字符串,字符串以0为结尾符
;参数: (ax)=dword型低位数据
; (dx)=dword型高位数据
; ds:si指向字符串首地址
;返回: 无
;;================================================
dwtoc:
push si
push ax
push dx
mov si, 0
mov bx, 0aH
mov di, 0
axs:
mov dx, 0
div bx
push dx
inc si
mov cx, ax
jcxz axok
jmp short axs
axok: pop ax
dxs:
mov dx, 0
div bx
push dx
inc si
mov cx, ax
jcxz dxok
jmp short dxs
dxok: mov cx, si
mov si, 0
axs1: pop di
add di, 30H
mov [si], di
inc si
loop axs1
mov [si], byte ptr '0'
pop ax
pop si
ret
;;名称:divdw
;;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型, 结果为dword型
;;参数:(ax)=dword型的低16位
;; (dx)=dword型的高16位
;; (cx)=除数
;;返回:(dx)=结果的高16位
;; (ax)=结果的低16位
;; (cx)=余数
;;=========================================================================
divdw: ;子程序定义开始,经典
push bx
push ax ; ax值暂时不用,先放入栈
mov ax,dx ; 注意要的是高位的商,所以做出发时高位放在ax里
mov dx,0 ; 32/16高位为0
div cx
; 除完后,ax放商,暂存到bx,dx放余数,因为公式里余数已经*65536,所以一定在dx里
mov bx,ax ; bx暂存商
pop ax ; 弹出低位
div cx ; 计算 [dx*65536+ax]/cx
mov cx,dx ; 余数传给了cx
mov dx,bx ; 保存余数
pop bx
ret ;子程序定义结束
code ends
end start
我把程序贴出来:
;程序功能是在屏幕指定行显示以下数据(其中包括人均值,要计算),其中有3个子程序,一个计算人均值,为了防止溢出而另外写的;一个是把数值转化成字符串的;另一个是在指定行显示字符串的。
assume cs:code, ds:data
data segment
dw 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983
dw 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992
dw 1993, 1994, 1995
dd 16, 22, 382, 1356, 2398, 8000, 16000, 24486, 50065, 97479, 140417, 197514
dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000
dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226
dw 11542, 14430, 15257, 17800
data ends
des segment
db 10 dup(0)
des ends
code segment
start:
mov ax, data
mov es, ax
mov ax, des
mov ds, ax
mov dh, 2
mov di, 0
mov si, 0
mov bp, 0
mov cx, 21
line:
push dx
mov ax, es:[di]
mov dx, 0
call dwtoc
mov al, 7
pop dx
inc dh
mov dl, 3
call show_str
push dx
mov ax, es:[2a+bp]
mov dx, es:[2c+bp]
call dwtoc
mov al, 7
pop dx
mov dl, 14
call show_str
push dx
mov ax, es:7e[di]
mov dx, 0
call dwtoc
mov al, 7
pop dx
mov dl, 28
call show_str
push dx
mov ax, es:02a[bp]
mov dx, es:02c[bp]
push cx
mov cx, es:7e[di]
call divdw
call dwtoc
pop cx
mov al, 7
pop dx
mov dl, 40
call show_str
inc dh
add di, 2
add bp, 4
loop line
ret
;;===================================================
;名称: show_str
;功能: 在指定位置,用指定颜色,显示一个用0结束的字符串
;参数: (dh)=行号(0~24)
; (dl)=列号(0~79)
; (al)=颜色
; ds:si指向字符串的首地址
;返回: 无
;;====================================================
show_str:
push es
push bx
push si
push ax
mov si, 0
mov al,0A0h
dec dh
mul dh
mov bx,ax
mov al,2
mul dl
sub ax,2
add bx,ax
mov ax,0B800h
mov es,ax
mov di,0
pop cx
mov al,cl
push cx
mov ch,0
s: mov cl,es:[si]
jcxz ok
mov es:[bx+di],cl
mov es:[bx+di+1],al
inc si
add di,2
jmp short s
ok: pop ax
pop si
pop bx
pop es
ret
;;===============================================
;名称: dwtoc
;功能: 将dword型数据转变为表示十进制数的字符串,字符串以0为结尾符
;参数: (ax)=dword型低位数据
; (dx)=dword型高位数据
; ds:si指向字符串首地址
;返回: 无
;;================================================
dwtoc:
push si
push ax
push dx
mov si, 0
mov bx, 0aH
mov di, 0
axs:
mov dx, 0
div bx
push dx
inc si
mov cx, ax
jcxz axok
jmp short axs
axok: pop ax
dxs:
mov dx, 0
div bx
push dx
inc si
mov cx, ax
jcxz dxok
jmp short dxs
dxok: mov cx, si
mov si, 0
axs1: pop di
add di, 30H
mov [si], di
inc si
loop axs1
mov [si], byte ptr '0'
pop ax
pop si
ret
;;名称:divdw
;;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型, 结果为dword型
;;参数:(ax)=dword型的低16位
;; (dx)=dword型的高16位
;; (cx)=除数
;;返回:(dx)=结果的高16位
;; (ax)=结果的低16位
;; (cx)=余数
;;=========================================================================
divdw: ;子程序定义开始,经典
push bx
push ax ; ax值暂时不用,先放入栈
mov ax,dx ; 注意要的是高位的商,所以做出发时高位放在ax里
mov dx,0 ; 32/16高位为0
div cx
; 除完后,ax放商,暂存到bx,dx放余数,因为公式里余数已经*65536,所以一定在dx里
mov bx,ax ; bx暂存商
pop ax ; 弹出低位
div cx ; 计算 [dx*65536+ax]/cx
mov cx,dx ; 余数传给了cx
mov dx,bx ; 保存余数
pop bx
ret ;子程序定义结束
code ends
end start