本帖最后由 jackz007 于 2021-1-1 21:14 编辑
问题出在堆栈不平衡,在用 debug 跟踪时,进入 show_str 时记录 sp 值,在要执行 ret 指令前,再看看 sp 值是否和前面记录的值一样?为什么会不一样,因为你在函数中使用了 push cx ,而在函数退出前,没有相应的退栈操作, 只要把 pop cx 指令提前到 jcxz ok 指令之前就可以解决问题。
我给楼主写了一份代码,供楼主参考。data segment public para 'data'
db 'welcome to masm!',0
data ends
stack segment stack para 'stack'
db 800h dup (0)
stack ends
code segment public para 'code'
assume cs:code,ds:data
start:mov ax,data
mov ds,ax
mov bx,0
mov dh,13 ;行
mov dl,32 ;列
mov cl,0fh ;颜色
mov si,0 ;ds:si指向字符串的首地址
push dx ;行列值入栈
push si ;待显示字符串偏移入栈
push cx ;字符颜色值入栈
call show_str
xor ax,ax
int 16h
stop: mov ax,4c00h
int 21h
show_str: push bp ; 在函数入口先保护现场,避免各寄存器的值因调用本函数而被改变
mov bp,sp
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
mov ax,0b800h
mov es,ax
mov si , word ptr[bp+06h] ; 待显示字符串偏移值
mov bx , word ptr[bp+08h] ; 行列值
mov al,bh
dec al
mov cl,0a0h
mul cl
mov di,ax
dec bl
xor bh,bh
shl bx,1
add di,bx ; di = 行列值对应的显存偏移
mov bx, word ptr[bp+04] ; 颜色
cld
s1: lodsb ; 从 ds:si 读入1个字符到 al
or al,al ; 是结束标志字符吗
jz s2 ; 如果是结束字符就跳走
stosb ; 把 al 存入显存 es:di
mov al,bl ; 把颜色字节交给al
stosb ; 把颜色字节存入显存 es:di
jmp short s1 ; 跳回显示下一个字符
s2: pop es ; 开始恢复现场
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov sp,bp
pop bp
ret
code ends
end start
|