| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 8405 人关注过本帖
标题:程序执行错误,B800段内存无法写入
只看楼主 加入收藏
ehszt
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:40
帖 子:1745
专家分:3216
注 册:2015-12-2
结帖率:100%
收藏
已结贴  问题点数:20 回复次数:10 
程序执行错误,B800段内存无法写入
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
图片附件: 游客没有浏览图片的权限,请 登录注册
搜索更多相关主题的帖子: 写入 data code add mov 
2020-07-30 22:22
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:20 
在dos的单工环境下,运行程式时,显存由程式本身操作,但若由debug载入,显存同时服务二者,也就是说,当程式写入显存(t)后,
debug的t程序也要工作,卷行,显示寄存器,段什么的一堆资料,于是显存早被改写了....
2020-07-31 05:54
ehszt
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:40
帖 子:1745
专家分:3216
注 册:2015-12-2
收藏
得分:0 
不用debug程序也不能正常执行啊,有什么办法吗?之前这个子程序是可以正常执行的。
2020-07-31 10:04
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
没有题目,看程式的结构,大概是输出一个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编辑过]

2020-07-31 13:12
ehszt
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:40
帖 子:1745
专家分:3216
注 册:2015-12-2
收藏
得分:0 
谢谢,有好多指令我还没学到,先保存起来,到时候再看吧!
2020-07-31 14:41
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
延伸探讨...

其实显示颜色字串不一定需要直接写显存,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编辑过]

2020-07-31 20:25
ehszt
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:40
帖 子:1745
专家分:3216
注 册:2015-12-2
收藏
得分:0 
程序按版主所说稍做修改
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的指令
从而导致程序死循环,请问是为什么,截图如下:
图片附件: 游客没有浏览图片的权限,请 登录注册










2020-07-31 22:04
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
程序代码:
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
2020-07-31 22:50
ehszt
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:40
帖 子:1745
专家分:3216
注 册:2015-12-2
收藏
得分:0 
回复 8楼 Valenciax
这样改真的可以了,不知道是为什么,是因为栈的原因吗?还是说jcxz只能在程序中用一次
2020-08-01 17:51
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
子程序中的栈针出和入必须平衡,进入时sp=离开时sp,否则ret弹回的ip就会不对

push cx

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


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


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

收到的鲜花
  • ehszt2020-08-01 18:45 送鲜花  2朵   附言:谢谢你哦!
2020-08-01 18:34
快速回复:程序执行错误,B800段内存无法写入
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.021825 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved