实验10.1求助
经过n个小时的苦思冥想,本吊终于磕磕绊绊的实现了程序,大佬勿喷。下面有个地方百思不得其解,为什么最后的ok标号处用ret的话就会出问题呢?在debug里跟着发现出现了莫名其妙的指令然后又继续开始执行之前的一些指令,我目前是用的jmp让他强行跳回到stop标号处。
太难了 = =
assume cs:code
data segment
db 'welcome to masm!',0
data ends
stack segment
db 8 dup (0)
stack ends
code segment
start:mov ax,data
mov ds,ax
mov bx,0
mov dh,8 ;行
mov dl,1 ;列
mov cl,2 ;颜色
mov si,0 ;ds:si指向字符串的首地址
call show_str
stop: mov ax,4c00h
int 21h
show_str:
mov ax,0b800h;
mov es,ax
sub dh,1
mov ah,0
mov al,160
mul dh
mov di,ax ;行偏移地址存在si中
sub dl,1
mov ah,0
mov al,2
mul dl
mov bx,ax ;列偏移地址存在bx中
not_ok:push cx
mov cl,;将字符按索引取出放入cl
mov ch,0
jcxz ok;判断是否为0
mov es:,cl;将字符放入对应显存位置
pop cx;恢复cx的值
mov es:,cl;写入颜色属性
add bx,2;移动到下个字节
inc si
jmp short not_ok
ok: jmp stop ;就是这里出的问题
code ends
end start
本帖最后由 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 ; 待显示字符串偏移值
mov bx , word ptr ; 行列值
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 ; 颜色
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 本帖最后由 monkey__ 于 2021-1-1 23:08 编辑
jackz007 发表于 2021-1-1 21:00
问题出在堆栈不平衡,在用 debug 跟踪时,进入 show_str 时记录 sp 值,在要执行 ret 指令前,再看 ...
谢谢~~~
但是把pop cx 前提好像就没办法正常退出那个假循环了 = = 尴尬
您的代码我试了下没有问题,就是有好多指令我还没学到,嘿嘿,等我再往后学下再来研读~~~
再次感谢~~~ monkey__ 发表于 2021-1-1 23:07
谢谢~~~
但是把pop cx 前提好像就没办法正常退出那个假循环了 = = 尴尬
按你的思路把 show_str 改了一下,根本没必要动用堆栈,把本来保存在 cl 中的颜色号转到其它寄存器中就好了。
show_str:mov ax,0b800h
mov es,ax
sub dh,1
mov al,160
mul dh
mov di,ax
sub dl,1
mov al,2
mul dl
add di,ax
mov al,cl
xor cx,cx
not_ok:mov cl,byte ptr
jcxz ok
mov byte ptr es:,cl
mov byte ptr es:,al
inc si
inc di
inc di
jmp short not_ok
ok: ret
页:
[1]