为什么 INT 31H 没有正确设置,即使 DPMI 主机处于活动状态?
Why isn't INT 31H set up properly even with a DPMI host active?
我一直在 MS-DOS 中进行大量的汇编编程试验。我读过 Windows 3.1 作为 DOS 程序的 DPMI 主机,并且 DPMI 使用中断 31h 进行函数调用。
让我们试一试。我在 Windows 3.1...
中打开 DOS 提示符
C:\WINDOWS>debug
-a100
23A4:0100 mov ax,0400
23A4:0103 int 31
23A4:0105
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=23A4 IP=0100 NV UP EI PL NZ NA PO NC
23A4:0100 B80004 MOV AX,0400
-p
AX=0400 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=23A4 IP=0103 NV UP EI PL NZ NA PO NC
23A4:0103 CD31 INT 31
-p
所以显然有些东西不起作用。
我再试一次,使用 T
race 命令而不是 P
roceed。这样它实际上会进入中断处理程序而不是跳过它。
AX=0400 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=23A4 IP=0103 NV UP EI PL NZ NA PO NC
23A4:0103 CD31 INT 31
-t
AX=0400 BX=0000 CX=0000 DX=0000 SP=FFE8 BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=F000 IP=FF01 NV UP DI PL NZ NA PO NC
F000:FF01 7261 JB FF64
-
让我们看看要执行什么...
-u
F000:FF01 7261 JB FF64
F000:FF03 63 DB 63
F000:FF04 6C DB 6C
F000:FF05 65 DB 65
F000:FF06 20564D AND [BP+4D],DL
F000:FF09 205669 AND [BP+69],DL
⋮
F000:FF18 53 PUSH BX
F000:FF19 0000 ADD [BX+SI],AL
F000:FF1B 0000 ADD [BX+SI],AL
F000:FF1D 0000 ADD [BX+SI],AL
F000:FF1F 0000 ADD [BX+SI],AL
-
...是的,这看起来不像是应该执行的任何操作。事实上,字节码看起来很像 ASCII 文本。果然...
-df000:ff01
F000:FF00 72 61 63 6C 65 20 56-4D 20 56 69 72 74 75 61 racle VM Virtua
F000:FF10 6C 42 6F 78 20 42 49 4F-53 00 00 00 00 00 00 00 lBox BIOS.......
F000:FF20 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
F000:FF30 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
F000:FF40 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
F000:FF50 00 58 4D CF CF 89 C0 89-C0 89 C0 89 C0 89 C0 FC .XM.............
F000:FF60 5F 53 4D 5F 7D 1F 02 05-FF 00 00 00 00 00 00 00 _SM_}...........
F000:FF70 5F 44 4D 49 5F 58 C2 01-00 10 0E 00 0A 00 25 00 _DMI_X........%.
F000:FF80 00 .
-
这显然不是 DPMI 处理程序。无论如何,如果我越过 JB FF64
,它将继续到 DB 63
(“Oracle”中的 'c'),这就是导致无效指令错误的原因。或者,如果设置了进位标志,它将进行跳转并遇到它解释为 JGE FF85
指令的内容。如果标志是这样的,它不会跳转,它最终会到达另一个无效指令。否则,它将[BX+SI]
处的字节增加AL
中的值105次,之后的字节77字节增加BL
中的值一次,最后重启VM,因为下一条指令是实模式复位向量。 (在 v86 模式下,但我猜 Windows 3.1 允许。)
长话短说,很明显在 INT 31H 没有安装 DPMI 处理程序,这显然应该是这样。一些额外的信息:
您可能已经注意到我只输入了 int 31
,而不是 int 31h
。这不是错误; debug
到处都使用十六进制。如您所见,它没有尝试将图形模式位图字体作为代码执行。 :P
我尝试使用 Qualitas MAX 而不是 Windows 3.1,并且根本没有 DPMI 主机,并且在两种情况下都得到了相同的结果。 (当然,减去 Windows 3.1 错误对话框。)
考虑到这一点,谁能告诉我我做错了什么?
DPMI的Real/Virtual86模式接口只有中断2Fh服务1687h。 returns 一个可以用来进入保护模式的入口点。中断 31h 服务仅在保护模式下可用。这是小型 DPMI 客户端的 an example。进入保护模式相关代码:
mov ax, 1687h
int 2Fh
test ax, ax ; DPMI host installed?
jnz nohost
push es ; save DPMI entry address
push di
test si, si ; host requires client-specific DOS memory?
jz .nomemneeded ; no -->
mov bx, si
mov ah, 48h
int 21h ; allocate memory
jc nomemory
mov es, ax
.nomemneeded:
; (message and breakpoint omitted)
mov bp, sp
mov ax, 0001h ; start a 32-bit client
call far [bp] ; initial switch to protected-mode
jnc initsuccessful
initfailed:
保护模式一般通过执行PM interrupt 21h service 4Ch(随后也传递给DOS 86M handler,从而终止DOS进程)退出保护模式。
顺便说一句,要调试 DPMI 客户端,您可能需要使用 FreeDOS DebugX 或 my fork lDebugX。
我一直在 MS-DOS 中进行大量的汇编编程试验。我读过 Windows 3.1 作为 DOS 程序的 DPMI 主机,并且 DPMI 使用中断 31h 进行函数调用。
让我们试一试。我在 Windows 3.1...
中打开 DOS 提示符C:\WINDOWS>debug
-a100
23A4:0100 mov ax,0400
23A4:0103 int 31
23A4:0105
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=23A4 IP=0100 NV UP EI PL NZ NA PO NC
23A4:0100 B80004 MOV AX,0400
-p
AX=0400 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=23A4 IP=0103 NV UP EI PL NZ NA PO NC
23A4:0103 CD31 INT 31
-p
所以显然有些东西不起作用。
我再试一次,使用 T
race 命令而不是 P
roceed。这样它实际上会进入中断处理程序而不是跳过它。
AX=0400 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=23A4 IP=0103 NV UP EI PL NZ NA PO NC
23A4:0103 CD31 INT 31
-t
AX=0400 BX=0000 CX=0000 DX=0000 SP=FFE8 BP=0000 SI=0000 DI=0000
DS=23A4 ES=23A4 SS=23A4 CS=F000 IP=FF01 NV UP DI PL NZ NA PO NC
F000:FF01 7261 JB FF64
-
让我们看看要执行什么...
-u
F000:FF01 7261 JB FF64
F000:FF03 63 DB 63
F000:FF04 6C DB 6C
F000:FF05 65 DB 65
F000:FF06 20564D AND [BP+4D],DL
F000:FF09 205669 AND [BP+69],DL
⋮
F000:FF18 53 PUSH BX
F000:FF19 0000 ADD [BX+SI],AL
F000:FF1B 0000 ADD [BX+SI],AL
F000:FF1D 0000 ADD [BX+SI],AL
F000:FF1F 0000 ADD [BX+SI],AL
-
...是的,这看起来不像是应该执行的任何操作。事实上,字节码看起来很像 ASCII 文本。果然...
-df000:ff01
F000:FF00 72 61 63 6C 65 20 56-4D 20 56 69 72 74 75 61 racle VM Virtua
F000:FF10 6C 42 6F 78 20 42 49 4F-53 00 00 00 00 00 00 00 lBox BIOS.......
F000:FF20 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
F000:FF30 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
F000:FF40 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
F000:FF50 00 58 4D CF CF 89 C0 89-C0 89 C0 89 C0 89 C0 FC .XM.............
F000:FF60 5F 53 4D 5F 7D 1F 02 05-FF 00 00 00 00 00 00 00 _SM_}...........
F000:FF70 5F 44 4D 49 5F 58 C2 01-00 10 0E 00 0A 00 25 00 _DMI_X........%.
F000:FF80 00 .
-
这显然不是 DPMI 处理程序。无论如何,如果我越过 JB FF64
,它将继续到 DB 63
(“Oracle”中的 'c'),这就是导致无效指令错误的原因。或者,如果设置了进位标志,它将进行跳转并遇到它解释为 JGE FF85
指令的内容。如果标志是这样的,它不会跳转,它最终会到达另一个无效指令。否则,它将[BX+SI]
处的字节增加AL
中的值105次,之后的字节77字节增加BL
中的值一次,最后重启VM,因为下一条指令是实模式复位向量。 (在 v86 模式下,但我猜 Windows 3.1 允许。)
长话短说,很明显在 INT 31H 没有安装 DPMI 处理程序,这显然应该是这样。一些额外的信息:
您可能已经注意到我只输入了
int 31
,而不是int 31h
。这不是错误;debug
到处都使用十六进制。如您所见,它没有尝试将图形模式位图字体作为代码执行。 :P我尝试使用 Qualitas MAX 而不是 Windows 3.1,并且根本没有 DPMI 主机,并且在两种情况下都得到了相同的结果。 (当然,减去 Windows 3.1 错误对话框。)
考虑到这一点,谁能告诉我我做错了什么?
DPMI的Real/Virtual86模式接口只有中断2Fh服务1687h。 returns 一个可以用来进入保护模式的入口点。中断 31h 服务仅在保护模式下可用。这是小型 DPMI 客户端的 an example。进入保护模式相关代码:
mov ax, 1687h
int 2Fh
test ax, ax ; DPMI host installed?
jnz nohost
push es ; save DPMI entry address
push di
test si, si ; host requires client-specific DOS memory?
jz .nomemneeded ; no -->
mov bx, si
mov ah, 48h
int 21h ; allocate memory
jc nomemory
mov es, ax
.nomemneeded:
; (message and breakpoint omitted)
mov bp, sp
mov ax, 0001h ; start a 32-bit client
call far [bp] ; initial switch to protected-mode
jnc initsuccessful
initfailed:
保护模式一般通过执行PM interrupt 21h service 4Ch(随后也传递给DOS 86M handler,从而终止DOS进程)退出保护模式。
顺便说一句,要调试 DPMI 客户端,您可能需要使用 FreeDOS DebugX 或 my fork lDebugX。