发信人: torvalds()
整理人: smallhors(1999-07-22 21:29:35), 站内信件
|
与各位同感, 随着Windows95,Windows98的广泛应用, DOS正离我们越来越远 . 但
我觉得在诸多的操作系统中, DOS的结构比较简单, 便于研究; 而且它的一些未公 开
特性还未被我们所完全了解, 但某些特性尚有价值; 再者DOS作为一个久经考验的 操
作系统, 在对它的研究过程中, 可以吸取一些编程的经验, 因此DOS在今天还是有 其
研究价值的. 我在一个4.5GB的硬盘上作了4个互相独立的Primary DOS分区, 第一 个
分区大小为2GB, 用于装Windows98, 第二个分区用于装MSDOS6.22. 但我在实践中 发
现, 系统安装后, DOS不能正常启动, 而显示出错. 对于这一问题, 我做了以下的 摸
索, 并得以解决. 特写以下这段文字, 以作交流.
问题分析
启动时, 屏幕上显示了:
Non-System disk or disk error
Replace and press any key when ready
字符串, 由于这样的字符串在硬盘主引导区中是找不到的, 而"Starting MS-DOS .
.."的字符串又并未在屏幕上出现, 因此我判断:启动时, 硬盘主引导程序已经成 功
地执行了, 而是在DOS引导程序执行时产生了错误. 用如下的DEBUG小程序读取硬 盘
主引导区:
MOV AX,0201
MOV BX,0200
MOV CX,0001
MOV DX,0080
INT 13
INT 3
然后用以下这段DEBUG小程序读出DOS引导程序:
MOV AX,0201
MOV BX,0500
MOV CX,[03D0]
MOV DH,[03CF]
MOV DL,80
INT 13
INT 3
我分析了一下500至6FF的程序, 发现程序中有3处地址在CALL语句后出现过:
0652,0660,0681, 地址0652处的子程序如下:
LODSB
OR AL,AL
JZ 0680
MOV AH,0E
MOV BX,0007
INT 10
JMP 0652
显然是显示某一个以0h结尾的字符串, 而这段显示字符串的程序只有在引导出错 时
才会被调用. 地址0681处的子程序如下:
MOV AH,02
MOV DX,[7C4D]
MOV CL,06
SHL DH,CL
OR DH,[7C4F]
MOV CX,DX
XCHG CH,CL
MOV DL,[7C24]
MOV DH,[7C25]
INT 13
RET
而整段引导程序中只有在0681至069D的这段子程序中, 出现了INT 13这句读盘的
中断调用, 所以唯有这段程序是读盘用的, 而且地址7C4D存放了磁道号, 地址7C 4F
存放了扇区号, 地址7C25存放了磁头号, 地址7C24存放了硬盘号(80:第一硬盘,
81:第二硬盘 ...)再看0660处的子程序:
CMP DX,[7C18]
JNB 067F
DIV WORD PTR [7C18]
INC DL
MOV [7C4F],DL
XOR DX,DX
DIV WORD PTR [7C1A]
MOV [7C25],DL
MOV [7C4D],AX
CLC
RET
STC
RET
程序中除了地址7C4F,7C25,7C4D外, 又用到了地址7C18和7C1A, 而且地址7C18
的值直接影响到了0660子程序能否完整执行, 十分重要. 于是, 我抄录了手
上2个硬盘中6个分区同一地址的值, 发现同一硬盘不同分区中的值相同, 而不
同硬盘间分区中的值就不同, 所以这个地址的值和硬盘有关, 分别比较这两组
数据和这两个硬盘的参数的对应情况, 才知道地址7C18存放了每道扇区数, 地
址7C1A存放了磁头数. 了解了这5个地址的意义, 再看这段子程序, 不难发现这
段子程序的作用是将逻辑扇区号换算成对应的磁道号, 磁头号和扇区号. 那么
为什么先要将DX和每道扇区数作比较呢? 其实, 就是这句语句使得程序不会被
挂起. 助记符DIV是使计算机做一次无符号除的运算, 由于这句的操作数是字,
所以被除数是DX,AX, 除数是操作数, 商放在AX中, 余数放在DX中, 如果被除数
是零或者商过大与AX计数范围不符, 就会发生除错误故障(中断0). AX的最大值
为FFFF, FFFF和任意一个数相乘时, 结果的最高位必定小于乘数, 所以此处的
这句比较语句是为了防治商大于累加器AX的取值范围. 扇区数的最大值为3F,
与AX的允许最大值相乘为3EFFC1, 这个值即是DOS引导时的最大可寻逻辑扇区号,
将近2GB左右. 而我的这一分区起始于2GB后, 因此必然执行JNB 067F, 然后
执行STC, 使进位标志置1, 再返回主程序:
CALL 0660
JB 05ED
...
05ED: MOV SI,7D9E
CALL 0652
显示出错信息. 从理论上找到出错原因后, 我将这段程序拷贝到7C00处, 用单步
执行的方法, 从实践中再分析一下, 果然和理论分析结果完全一致.
问题解决
出错是因为商大于FFFF, 大于了字操作中存放商的累加器AX的允许最大值,
如果改为双字操作, 即可把商放入EAX中, 而EAX的允许最大值为FFFFFFFF, 程序
便可正常执行了. 但这一修改后的代码长度必然大于原代码的长度, 故必须另找
一些空间来存放额外代码. 我在此选用的是硬盘主引导区后的一个保留扇区来放
置额外代码.(但有一些应用程序也会有可能使用到这个扇区, 所以这也许会损失
一些兼容性, 不过我个人觉得这个方法比较简单. 如若冲突, 换个扇区放代码即
可)修改后的程序必须做到:首先, 要有一段程序将额外代码装入内存; 然后, 在
DOS引导程序需做硬盘地址转换时, 使其使用新的代码. 由于DOS引导区的剩余空
间太小, 所以引入额外代码的程序放在硬盘主引导区的剩余空间中, 以Windows9 8
的硬盘主引导区为例:(DOS, Windows95的硬盘主引导区与其相似, 而且剩余空间
更大)先用DEBUG:
MOV AX,0201
MOV BX,7C00
MOV CX,0001
MOV DX,0080
INT 13
INT 3
将硬盘主引导程序调入内存7C00处, 从7C00处反汇编可得如下代码:
XOR AX,AX
MOV SS,AX
MOV SP,7C00
STI
PUSH AX
POP ES
PUSH AX
POP DS
CLD
MOV SI,7C1B
MOV DI,061B
PUSH AX
PUSH DI
MOV CX,01E5
REPZ
MOVSB
RETF
MOV SI,07BE
MOV CL,04
...
我将MOV CX,01E5这句语句改为CALL 7D90, 再在7D90处写入以下代码:
PUSH AX
PUSH BX
PUSH DX
PUSH SI
PUSH DI
MOV AX,0201
MOV BX,7E00
MOV CX,0002
MOV DX,0080
INT 13
POP DI
POP SI
POP DX
POP BX
POP AX
MOV CX,01E5
RET
用:
MOV AX,0301
MOV BX,7C00
MOV CX,0001
MOV DX,0080
INT 13
INT 3
将其写回硬盘, 再用:
MOV AX,0201
MOV BX,7E00
MOV CX,0002
MOV DX,0080
INT 13
INT 3
调入硬盘主引导区后的第一个保留扇区至地址7E00, 写入额外代码:(这是在DOS
引导区中写不下的一部分)
DB 66
XOR DX,DX
DB 66
XOR CX,CX
OR CX,[7C1A]
DB 66
DIV CX
MOV [7C25],DL
MOV [7C4D],AX
JMP 7D7F
用:
MOV AX,0301
MOV BX,7E00
MOV CX,0002
MOV DX,0080
INT 13
INT 3
将其写回硬盘. 最后, 用:
MOV AX,0201
MOV BX,7C00
MOV CX,[03D0]
MOV DH,[03CF]
MOV DL,80
INT 13
INT 3
调入DOS引导程序至地址7C00, 用如下代码:
PUSH AX
PUSH DX
DB 66
XOR DX,DX
POP AX
MOV CL,10
DB 66
SHL AX,CL
POP AX
DB 66
XOR CX,CX
OR CX,[7C18]
DB 66
DIV CX
INC DL
MOV [7C4F],DL
JMP 7E00
CLC
RET
覆盖地址7D60处的原代码, 代码的修改工作就完成了. 代码中有一点要说明的
是:多次出现DB 66语句的原因, 是因为DEBUG不能编译类似XOR EDX,EDX之类含
32位寄存器的语句, 因而需自己输入OPSIZ这一前缀,(原本是机器在编译时, 根
据需要自动加上的)使在16位本机方式下, 下一句语句中的操作数大小按32位定
义. 而DEBUG又不能编译OPSIZ前缀, 而又因为前缀OPSIZ的机器代码为66h, 因
此用DB 66代替. 这样类似于DB 66, XOR DX,DX的语句, 在执行时即以XOR EDX,
EDX执行了.
虽然, 以上的代码在我自己的机器上运行正常, 但各种机型不同, 在修改前
对要改的部分做好备份. 现就我估计在286上无法运行, 因此还望各位高人指教.
(Email:[email protected])
-- ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.109.33.85]
|
|