读书人

大家来看看小弟我的程序不能返回DOS

发布时间: 2012-02-02 23:57:14 作者: rapoo

大家来看看,我的程序不能返回DOS了!哪位大侠可以跟踪INT 21探查究竟?
程序功能:读引导山区,然后以16进制方式显示在屏幕上。程序可以正确的读引导扇区,显示的结果也都正确,最后调用的一个子过程也正确返回。

问题在于:执行mov ah,4c,再执行int 21指令时,失去响应,无法返回DOS,就连按下Crlt+Alt+Del也不响应。我怀疑唯一的可能是覆盖了dos的某个模块?但是内存完全是dos分配的,我又没干什么非法的勾当。

补充:编译时总提示没有堆栈段,我怕dos看不到我的堆栈段,我设置了1K大小。

代码如下:
DATAS SEGMENT
db 4096 dup(0)
DATAS ENDS

STACKS SEGMENT
DB 1024 DUP(0)
STACKS ENDS
ReadSector PROTO NEAR
MEM_TO_HEX PROTO FAR
.386P
CODES SEGMENT USE16
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOVAX,DATAS
MOVDS,AX
MOVAX,STACKS
MOVSS,AX
MOV SP,1024
PUSHDS
MOV AX,01H ;读取逻辑扇区1
MOVCL,01H ;读取1个扇区长度
CALLReadSector
MOVAX,512
PUSHAX
PUSHBX
MOVAX,ES;读取缓冲区段值
MOVDS,AX;设置为DS,因为DS被MEM_TO_HEX过程默认使用
XORAX,AX
PUSHAX;压入显存的偏移地址
MOVAX,0B800H;ES被MEM_TO_HEX过程默认使用
MOVES,AX
CALLMEM_TO_HEX
POPDS
MOVAH,4CH
INT21H
;*********************************************************************
;软磁盘逻辑扇区编码方式:
;0头0道1扇区~18扇区:对应逻辑扇区号1~18
;1头0道1扇区~18扇区:对应逻辑扇区号19~36
;0头1道1扇区~18扇区:对应逻辑扇区号37~54
;1头1道1扇区~18扇区:对应逻辑扇区号55~72
;
;BIOS中断 int13H的调用规范
;子中断号ah=02h读磁盘al=要读取的扇区数
;ch=磁道号cl=起始扇区号
;dh=磁头号es:bx 缓冲区地址
;*********************************************************************
;---------------------------------
;函数名:
ReadSectorPROCNEAR
;入口参数
;ax=逻辑扇区号cl=要读取的扇区个数es:bx 缓冲区地址
;---------------------------------
pushbp
movbp,sp
subsp,2
mov[bp-2],cl
pushbx
pushax
mov bl,37
divbl;商为磁道号
movch,al;填写磁道号
popax
mov bl,19
divbl
movdh,al;商为磁头号
movcl,ah;余数为起始扇区号
moval,[bp-2];填充要读取的扇区数
mov ah,02h ;读扇区
movdl,00h;目标存储介质:软磁盘
pop bx
int13h
addsp,2
popbp
ret
ReadSectorENDP
;*********************************************************************
;函数功能:转化指令长度的内存区块为ASCII,转储到目标内存块,目标
; 内存块长度应该是源内存块的4倍,如果内存块的内容均为压
; 缩BCD码,则函数恰好将其转化为ASCII码。
;入口参数:参数3:目标内存块地址,参数2:源内存块地址,参数1:源
; 内存块大小
; 参数大小:均为2个字节,参数顺序,自右向左
; 注意: 要在16位代码段中使用本函数,子过程已经通过了作者的初步
; 测试,欢迎大家测试并使用。


;*********************************************************************
MEM_TO_HEX PROC FAR
PUSHBP
MOVBP,SP
MOVDI,[BP+06H];提取目标内存块地址
MOVSI,[BP+08H];提取源内存块地址
MOVCX,[BP+0AH];提取源内存块长度(单位:字节)
MOV AH,0CH ;设置前景背景
LCX:
MOVAL,[SI];读源缓冲区中的一个字节
MOVBH,AL;保存AL的高半字节
MOVBL,2H;AL中的2个BCD压缩码要分两次转化
SHR AL,4H
LBL:
ANDAL,0FH;将AL低半字节转化成十六进制
CMPAL,09H
JAA
ORAL,30H;转化数字(0~9)成ASCII
JMPB
A: ADD AL,37H ;转化字母(A~F)成ASCII
B:MOVES:[DI],AX;存入目标内存区(显存)
INCDI
INCDI;目标内存指针加2
MOVAL,BH;恢复AL的高半字节
DECBL;循环计数器减1
JNZLBL
INCSI;源内存指针加1
LOOPLCX
POPBP
RET06H
MEM_TO_HEX ENDP

CODES ENDS
END START

[解决办法]
呵呵, 仔细看了下 int13h 相关的, 应该是没有设置正确的 ES:BX 造成的吧, 尤其是 ES. 缺省的 ES 指向 psp, bx 随环境有不同, 这里一般为 0. 这样 ES:BX 指向了 psp, 导致导入扇区覆盖了 psp, 引发 dos 崩溃.
....
START:
MOV AX,DATAS
MOV DS,AX
MOV ES, AX ;* 这里设置 es 指向 DATAS 段
MOV AX,STACKS
MOV SS,AX
MOV SP,1024
PUSH DS
MOV AX,01H ;读取逻辑扇区1
MOV CL,01H ;读取1个扇区长度
mov bx, offset ... ;* 这里设置 bx 指向数据段的读入缓冲区空间, 给那个命名下
CALL ReadSector
....

上面的代码在虚拟机上验证过了.

读书人网 >汇编语言

热点推荐