注册 登录
编程论坛 汇编论坛

程序执行错误,B800段内存无法写入

ehszt 发布于 2020-07-30 22:22, 8471 次点击
STACKS SEGMENT
    dw 10 dup(0)
STACKS ENDS
data segment
    db 10 dup(0)
data ends

code  segment
assume  cs:code,ss:stacks,ds:data
start:   
        mov ax,stacks
        mov ss,ax
        mov sp,20
        mov ax,12666
        mov bx,data
        mov ds,bx
        mov si,0
        call dtoc
        
        mov dh,8
        mov dl,3
        mov cl,2
        call show_str
               
        mov ax, 4c00h
        int 21h

dtoc:
        add si,2
        mov bx,10
        mov dx,0
    s:  div bx
        mov cx,ax
        add dx,30h
        mov ds:[si],dx
        mov dx,0
        jcxz ok
        add si,2
        jmp short s
        ok: ret

show_str:
        mov al,0a0h
        mul dh
        mov bx,ax
        mov al,2
        mul dl
        add bx,ax
        mov ax,0b800h
        mov es,ax
    s1:
        mov ch,0
        push cx
        mov cx,si
        jcxz ok1
        pop cx
        mov es:[bx+1],cl  ;调试到这一段发现,cl的2无法写入到es:[507]中,指令运行完es:[507]中是F0
        mov al,ds:[si]
        mov es:[bx],al    ;es:[506]中是20,而不是31
        add bx,2
        sub si,2
        jmp short s1
        ok1:ret
code  ends
end   start
只有本站会员才能查看附件,请 登录
10 回复
#2
Valenciax2020-07-31 05:54
在dos的单工环境下,运行程式时,显存由程式本身操作,但若由debug载入,显存同时服务二者,也就是说,当程式写入显存(t)后,
debug的t程序也要工作,卷行,显示寄存器,段什么的一堆资料,于是显存早被改写了....
#3
ehszt2020-07-31 10:04
不用debug程序也不能正常执行啊,有什么办法吗?之前这个子程序是可以正常执行的。
#4
Valenciax2020-07-31 13:12
没有题目,看程式的结构,大概是输出一个ax的十进制到指定的座标吧.又是那一句,写法有点问题.
作为十进制字串,应该是紧致排在一起,比如ax=1234h,转换后内存字串就应该是 34 36 38 30 00,其中00是结束符
这样才方便输出,重写的子程序htod,意思是16进制转10进制,输出采用之前楼主另一个问题,我回答的一个子程序,合起就是了.

程序代码:

DATA SEGMENT
  StrBuf db 10 dup(0)
DATA ENDS
CODES SEGMENT
    ASSUME CS:CODES,DS:DATA
START:
    mov ax,data
    mov ds,ax
    mov es,ax   
    cld            ;清除方向标志
    mov ax,12666      ;任意值
    lea di,StrBuf    ;数字字串地址
    call htod        ;转换ax值为数字字串

    MOV dh,8            ;行号
    MOV dl,3            ;列号
    mov cl,2             ;颜色
    lea si,StrBuf
    call show_str    ;输出
    mov ax,4c00h
    int 21h
        
htod:        ;输出数值转字符串并存入es:di的子程序
    mov cx,0     ;清0,初始化
    mov bx,10     ;除法准备
@@:
    mov dx,0     ;清0
    div bx     ;ax /10,若1234,除10后,dl得余数4
    push dx     ;保存, ax=1234,依次保存4,3,2,1
    inc cx     ;累加个数
    or ax,ax    ;是否已除尽
    jnz @b     ;不是,再除
@@:
    pop ax    ;后入先出,先印出第一数,然后第二....
    or al,'0'    ;转ascii
    stosb    ;存入es:[di],di+1
    loop @b     ;下一个
    mov al,0    ;0结束符
    stosb    ;存入es:[di],作为结束符
    ret
            
show_str:
    mov al,80*2   ;一行有160个字节
    mul dh        ;ax保存第n行前的n行字节数
    mov dh,0      ;清除
    shl dl,1      ;dl * 2
    add ax,dx     ;加上ax
    mov di,ax     ;存入di
    mov ax,0b800h ;段地址
    mov es,ax   
    mov ah,cl     ;取颜色
    cld           ;清除方向,影晌lodsb等指令,累加
s:  
    lodsb         ;相当于2条指令, mov al,ds:[si] .... inc si
    or al,al      ;al是否0 ?
    jz @f         ;是,离开
    stosw         ;相当于2条指令, mov es:[di],ax ... add di,2
    jmp short s   ;回圈
@@: ret

CODES ENDS
    END START



[此贴子已经被作者于2020-7-31 13:43编辑过]

#5
ehszt2020-07-31 14:41
谢谢,有好多指令我还没学到,先保存起来,到时候再看吧!
#6
Valenciax2020-07-31 20:25
延伸探讨...

其实显示颜色字串不一定需要直接写显存,bios提供的int10h,函数13h就可以做到,参数分别是
es:bp=字串起点,cx=字串长度,bl=颜色,dl=列,dh=行,al=模式,通常=0,然后ah=13h,调用int10h就是.

另外,若配合masm提供的宏,写颜色字串会是十分简单的操作.
masm, m + asm, macro assembler, 就是宏汇编器的意思,宏写法是

@宏名称 MACRO 参数1,参数2....参数n

  宏本身
 
ENDM

把显示字串写成一个宏,放在文件最前
@DispStr MACRO DStr,Column,Row,Color
..
..
ENDM

比如要在座标(10,3)输出Strbuf字串,颜色=绿,一句指令就可以
@DispStr StrBuf,10,3,2

下面是将show_str子程序改为宏,为了检证这个宏能处理不同长度的字串,分别用了三个大小不一的数字.

程序代码:

.286
;--------------------------------------------------------------------------------------------------
;
显示颜色字串的宏
@DispStr MACRO DStr,Column,Row,Color  ;调用int10h,ah=13h输出颜色字串,4参数分别是字串,列,行,颜色
    pusha        ;保存所有寄存器
    push es        ;保存ES
    push ds        ;
    pop es        ;ES=DS ------------------------------------------|
    lea di,DStr    ;取得字串地址                                     |
    mov al,0    ;AL=0                                              |
    mov cx,0ffffh    ;最大初始化值                                   |
    cld        ;清除方向                                            |--找字串长度
    repnz scasb    ;重覆找es:di中(cx=长度)有没有al,找到则零标志=0        |
    jnz @f        ;找不到,离开                                       |
    sub cx,0ffffh    ;减去初始值                                     |
    not cx        ;反,得cx=字串长度-----------------------------------|
    lea bp,DStr    ;取得字串地址 -------------------------------------------------|
    mov bl,Color    ;颜色                                                        |
    mov bh,0    ;显示页=0                                                        |  int10h
    mov dh,Row    ;行(x)                                                        |--ah=13h
    mov dl,Column    ;列(y)                                                     |  输出函数  
    mov ax,1300h    ;输出字串函数,dl=列,dh=行,bl=色,cx=长度,es:bp=字串地址,al=模式0   |
    int 10h         ;调用int10h  -----------------------------------------------|
@@:
    pop es        ;取回es
    popa        ;取回所有寄存器
ENDM            ;宏结束
;
--------------------------------------------------------------------------------------------------
DATA SEGMENT
  StrBuf db 10 dup(0)
DATA ENDS
CODES SEGMENT
    ASSUME CS:CODES,DS:DATA
START:
    mov ax,data
    mov ds,ax
    mov es,ax   
    cld                ;清除方向标志
    mov ax,12666          ;任意值
    lea di,StrBuf        ;数字字串地址
    call htod            ;转换ax值为数字字串
   @DispStr StrBuf,3,8,2    ;绿色=2
    mov ax,54             ;任意值
    lea di,StrBuf        ;数字字串地址
    call htod            ;转换ax值为数字字串
   @DispStr StrBuf,20,11,6    ;黄色=6
    mov ax,1234             ;任意值
    lea di,StrBuf        ;数字字串地址
    call htod            ;转换ax值为数字字串
   @DispStr StrBuf,50,20,0Bh    ;亮蓝色=0bh

    mov ax,4c00h
    int 21h
        
htod:        ;输出数值转字符串并存入es:di的子程序
    mov cx,0     ;清0,初如化
    mov bx,10     ;除法准备
@@:
    mov dx,0     ;清0
    div bx     ;ax /10,若1234,除10后,dl得余数4
    push dx     ;保存, ax=1234,依次保存4,3,2,1
    inc cx     ;累加个数
    or ax,ax    ;是否已除尽
    jnz @b     ;不是,再除
@@:
    pop ax    ;后入先出,先印出第一数,然后第二....
    or al,'0'    ;转ascii
    stosb    ;存入es:[di],di+1
    loop @b     ;下一个
    mov al,0    ;0结束符
    stosb    ;存入es:[di],作为结束符
    ret

CODES ENDS
    END START


只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2020-7-31 20:37编辑过]

#7
ehszt2020-07-31 22:04
程序按版主所说稍做修改
STACKS SEGMENT
    dw 10 dup(0)
STACKS ENDS
data segment
    db 10 dup(0)
data ends

code  segment
assume  cs:code,ss:stacks,ds:data
start:   
        mov ax,stacks
        mov ss,ax
        mov sp,10
        mov ax,12666
        mov bx,data
        mov ds,bx
        mov si,0
        call dtoc
        
        mov dh,8
        mov dl,3
        mov cl,2
        call show_str      
        mov ax, 4c00h
        int 21h

dtoc:
        inc si
        mov bx,10
        mov dx,0
    s:  div bx
        mov cx,ax
        add dl,30h
        mov ds:[si],dl
        mov dx,0
        jcxz ok
        inc si
        jmp short s
        ok: ret

show_str:
        mov al,0a0h
        mul dh
        mov bx,ax
        mov al,2
        mul dl
        add bx,ax
        mov ax,0b800h
        mov es,ax
    s1: mov ch,0
        push cx
        mov cx,si
        jcxz ok1
        pop cx
        mov al,ds:[si]
        mov ah,cl
        mov es:[bx],ax
        add bx,2
        dec si
        jmp short s1
        ok1:ret
code  ends
end   start
可是我用debug监控,在show_str程序结束后不是运行mov ax,4c00h,而是运行一个ADC ax,d08e的指令
从而导致程序死循环,请问是为什么,截图如下:
只有本站会员才能查看附件,请 登录










#8
Valenciax2020-07-31 22:50
程序代码:

show_str:
        mov al,0a0h
        mul dh
        mov bx,ax
        mov al,2
        mul dl
        add bx,ax
        mov ax,0b800h
        mov es,ax
    s1: ;mov ch,0
        ;push cx
        ;mov cx,si
        ;jcxz ok1
        ;pop cx
        mov al,ds:[si]
        mov ah,cl
        mov es:[bx],ax
        add bx,2
        dec si
        jnz s1
        ;jmp short s1
        ok1:ret
#9
ehszt2020-08-01 17:51
回复 8楼 Valenciax
这样改真的可以了,不知道是为什么,是因为栈的原因吗?还是说jcxz只能在程序中用一次
#10
Valenciax2020-08-01 18:34
子程序中的栈针出和入必须平衡,进入时sp=离开时sp,否则ret弹回的ip就会不对

push cx

jcxz ...  ;中途离开,push,pop不能成对会令sp失衡
pop cx


再看一下代码,si减至0就可离开,根本不必这几句,可删
dec si
jnz s1 ;不为0则再来


[此贴子已经被作者于2020-8-1 18:36编辑过]

#11
ehszt2020-08-01 18:44
哦,知道了,谢谢!!
1