回 帖 发 新 帖 刷新版面

主题:关于子程序和栈的问题

学汇编几天了,在写子程序,可感觉自己写的很乱,完全没有风格之说,看书上说,如果子程序要用的相应的寄存器,那么要把该寄存器先压入栈以保存之前的数据,可我有个问题,如果一个寄存器被当做参数传入子程序,而子程序中又要用到寄存器该怎么办呢?我是把它压入栈等用的时候再弹出。。可。。。程序相当混乱。。希望有前辈指点下问题的所在
我把程序贴出来:
;程序功能是在屏幕指定行显示以下数据(其中包括人均值,要计算),其中有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

回复列表 (共1个回复)

沙发

data segment
    dw 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983

定义的数据最好起个名,否则实在不方便访问。

函数 使用的寄存器先入栈,在结束前出栈。

当函数使用参数时,在调用函数前入栈,用bp保存sp后,
可使用[bp+xx]寻址 来访问入栈的参数.
函数结束后,弹出参数 可直接使用ret n。


上面的写的,在一般的汇编书籍都有介绍,
如果没有,
你可以到图书馆,淘换老外写的汇编教程。

我来回复

您尚未登录,请登录后再回复。点此登录或注册