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

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时,它可以让协处理器执行指令,但是当x87不存在时,模拟器可以仿真。

我非常熟悉如何通过移位和诸如此类来实现FPU操作。我想了解更多有关仿真器的这些调用的协议。我一直找不到文档。也许RE社区的成员之一呢?

评论

我会使用位移和遮罩进行成像以提取指数和尾数,然后使用定点数学来获取结果

我了解如何使用整数寄存器执行FP数学。我想知道的是用于调用FP仿真的绑定机制-那些int指令期望的寄存器。

转到ralf browns主页并下载软件包,其中一个软件包将包含int.com,您可以使用它们进行int调用,例如int.com 0x3c -ax 0xxx -bx 0xyyyy cs.cmu.edu/~ralf/files.html今天的日期INT.COM 0x21 -ah 0x2a AX = 2A00 BX = 0000 CX = 0000 DX = 0000 SI = 0000 DI = 0000 BP = FFAC SP = FFA0 CS = 0000 DS = 0000 ES = 0000 SS = 0000 CPU标志:0n00oditsz0a0p1c INT :0x21 AX = 2A02 BX = 0000 CX = 07E0 DX = 0316 SI = 0000 DI = 0000 BP = FFAC SP = FFA0 CS = 0000 DS = 0000 ES = 0000 SS = 0000 CPU标志:0N11odItSz0A0P1C DOSERR:0057(87)

这可能会有所帮助:delphigroups.info/2/d7/740.html

@JasonGeffner:谢谢,这正是我一直在寻找的链接。看来我的Ralf中断清单副本过时。

#1 楼

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

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

在没有错误指令陷阱的旧8086机器上,过去的长辈提出了一种仿真策略。所有x87指令都在D8-DF范围内(8个可能的值),其后是modrm和其他优缺点。如果在指令前加上FWAIT(操作码9B),则可以保证在modrm字节之前始终有两个字节的代码,看起来像9B Dx。但是,编译器将发出CD xx,而不是发出这两个字节,其中xx范围是34-3B(8个可能的值)。众所周知,CD是x86 int指令的编码。

当CPU执行int指令并到达34-3B的处理程序时,它将转到中断处理程序。如果没有可用的x87协处理器,则处理程序将模拟浮点指令,并在内存中保持协处理器状态。但是,如果存在x87协处理器,则处理程序将窥视返回堆栈以查看int指令的位置,并使用与9B Dx字节序列相对应的相应CD 3x字节序列覆盖该指令。然后,它将控制权返回给修补的指令,以便执行该指令。现在已经对其进行了修补,该指令是一条实际的FPU指令,并且该指令的未来执行将不再需要通过仿真器进行漫长的绕行。

如何处理中断3E的文档为仍然不行。但是,暂时,我有足够的信息来在Reko反编译器中实现x87仿真支持。

评论


自我答案不会(不应)让我们感到羞耻-学习是一件好事:P

–猫
16-3-22在15:45

太酷了-我记得当时回想起二进制文件中的中断调用-十几岁的我无法解释为什么协处理器操作码从未出现过。

–jsbueno
16 Mar 23 '16 at 0:59

你知道,我实际上记得那件事。不是细节,只是它使用INT代替了fpu操作码。

–JDługosz
16-3-23在3:36



现在,该功能已在Reko中实现,并且可以正常工作。

– JohnKällén
16 Mar 23 '16 at 7:52