MS-DOS 中 x87 浮点仿真的协议是什么?

逆向工程 x86
2021-06-25 02:16:36

我正在尝试在使用Borland C++编译的尘土飞扬的旧 MS-DOS 二进制文件上使用Reko 反编译器获得有用的结果,该二进制文件似乎正在执行大量浮点运算。我看到的代码序列像

mov ax,0x4D8C    ; segment selector
mov es,ax
int 0x3C         ; call x87 emulator??
fld dword ptr [<some address>]
sub sp,8
int 0x39         ; call x87 emulator??

...等等。粗略的搜索引擎搜索强烈暗示这些int指令正在调用 x87 仿真库;当 x87 存在时,它让协处理器执行指令,但当它不存在时,仿真器进行仿真。

我非常熟悉如何实施FPU 操作,包括轮班等等。我想了解更多的是这些对模拟器的调用的协议。我一直无法找到文档。也许 RE 社区的其中一位成员呢?

1个回答

没有什么比在 stackexchange 上问问题更能找到答案(或至少部分答案)而感到羞辱的了。找到以下源文件后,它开始变得有意义:

https://github.com/alexhenrie/wine/blob/master/dlls/krnl386.exe16/fpu.c

在旧的 8086 机器上,没有无效指令的陷阱,过去的长老们提出了一种仿真策略。所有 x87 指令都在D8-DF范围内(8 个可能的值),然后是 modrm 和其他优点。如果在指令前加上FWAIT(opcode 9B),就可以保证在 modrm 字节之前总是有两个字节的代码,看起来像9B Dx. 但是,编译器不会发出这两个字节,而是发出CD xx,其中 xx 范围为34- 3B(8 个可能的值)。众所周知,CD是x86int指令的编码

当 CPU 执行int指令并到达34-的处理程序时3B,它会转向中断处理程序。如果没有可用的 x87 协处理器,处理程序将模拟浮点指令,在内存中维护协处理器状态。然而,如果有一种协处理器的x87目前,该处理程序将偷看返回堆栈上看到int指示的位置,并覆盖它与适当的9B Dx字节序列中,对应于CD 3x字节序列。然后它将控制权返回给修补后的指令,以便执行。现在已经打好补丁,该指令是一条实际的 FPU 指令,以后执行这些指令将不再需要通过仿真器走很长的弯路。

关于如何处理中断的文档3E还没有出来。不过,就目前而言,我有足够的信息在 Reko 反编译器中实现 x87 仿真支持。