monkey__ 发表于 2021-1-1 17:16:51

实验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:00:23

本帖最后由 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:07:06

本帖最后由 monkey__ 于 2021-1-1 23:08 编辑

jackz007 发表于 2021-1-1 21:00
问题出在堆栈不平衡,在用 debug 跟踪时,进入 show_str 时记录 sp 值,在要执行 ret 指令前,再看 ...

谢谢~~~

但是把pop cx 前提好像就没办法正常退出那个假循环了 = = 尴尬

您的代码我试了下没有问题,就是有好多指令我还没学到,嘿嘿,等我再往后学下再来研读~~~

再次感谢~~~

jackz007 发表于 2021-1-2 00:02:35

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]
查看完整版本: 实验10.1求助