assembly 如何在Windows异常处理程序中设置MMX寄存器以模拟不支持的3DNow!说明书

5sxhfpxr  于 2023-04-30  发布在  Windows
关注(0)|答案(1)|浏览(141)

我试图恢复一个旧的Win32游戏,使用3DNow!指令集进行3D渲染。
在Win7 - Win10等现代操作系统上,不允许使用FADD或FPMUL等指令,程序会抛出异常。
由于3DNow!由于游戏中使用的指令非常有限,在我的VS 2008 MFC程序中我尝试使用向量异常处理来获取MMX寄存器的值,模拟了3DNow!指令由C代码执行,并将值推回到处理器3DNow!寄存器。
到目前为止,我成功地完成了前两步(我从ExceptionInfo->ExtendedRegisters字节数组偏移量32处获取mmx寄存器值,并使用浮点型C指令进行计算),但我的问题是,无论我如何尝试更新MMX寄存器值,寄存器值似乎都保持不变。
假设我的_asm语句可能是错误的,我还使用像这样的简单语句做了一些最小测试:

_asm movq mm0 mm7

执行此语句时没有进一步的异常,但在检索MMX寄存器值时,我仍然发现原始值未更改。
我怎样才能使作业有效?

l7wslrjt

l7wslrjt1#

在Win7 - Win10等现代操作系统上,不允许使用FPADD或FPMUL等指令
更有可能是你的CPU不支持3DNow!AMD放弃了它的推土机家庭,英特尔从来没有支持它。因此,除非你在Athlon 64/ Phenom(或Via C3)上运行现代Windows,否则你的CPU不支持它。
(Fun PREFETCHW最初是一个3DNow!指令,并且 is 仍然受支持(具有其自己的CPUID功能位)。在很长一段时间内,Intel CPU将其作为NOP运行,但Broadwell和更高版本(IIRC)实际上会通过Read-For-Ownership将缓存行预取为独占状态。)
除非这个游戏只在AMD硬件上运行过,否则它必须有一个避免3DNow的代码路径。修复其CPU检测停止检测您的CPU具有3DNow。(也许你有一个最近的AMD,它假设 * 任何 * AMD有3DNow?)
(更新:OP的注解说其他代码路径由于某种原因不起作用。这是个问题)
从异常处理程序返回可能会从保存的状态恢复寄存器,因此在异常处理程序中更改寄存器值对主程序没有影响也就不足为奇了。
不过,显然更新内存中的ExtendedRegisters并不能解决这个问题,所以这只是保存状态的副本。
从异常处理程序修改MMX寄存器的答案可能与修改整数或XMM寄存器的答案相同,因此请查阅MS的文档。
替代建议:

**重写3DNow代码以使用SSE 2。(你说只有一小部分?)SSE 2是x86-64的基线,并且对于32位x86通常是安全的。

如果没有source,您仍然可以修改使用3DNow的少数函数的asm。您可以直接更改指令,使用64位加载/存储到XMM寄存器中,而不是3DNow!64位加载/存储,并将PFMUL替换为mulps等。(如果您用完了寄存器,并且3DNow代码使用了内存源操作数,这可能会有点麻烦。addps xmm0, [mem]需要16 B对齐的内存,并执行16字节加载。因此,您可能不得不添加溢出/重新加载以借用另一个寄存器作为临时)。

如果你没有足够的空间来重写函数,那么在你有空间添加新代码的地方放一个jmp

大多数3DNow指令在SSE中都有等效的,但您可能需要一些额外的movaps指令来复制寄存器以实现PFCMPGE。如果可以忽略NaN的可能性,则可以将cmpps与不小于 predicate 一起使用。(没有AVX,SSE仅具有基于小于或不小于的比较 predicate )。
PFSUBR很容易模拟一个备用寄存器,只需复制和subps反转。(或以“降”字,或以“降”字,或以“降”字,或以“降”字。PFRCPIT1(refinement的倒数-sqrt第一次迭代)等没有单指令实现,但如果您不想使用implement Newton-Raphson iterations with mulps and addps(或AVX vfmadd),则可以使用sqrtpsdivps。现代的CPU比这个游戏设计的要快得多。
您可以使用movsd(SSE 2双精度加载/存储指令)将一对单精度浮点数从内存加载/存储到XMM寄存器的底部64位。您也可以使用movlps存储一对,但仍然使用movsd加载,因为它将上半部分归零而不是合并,因此它不依赖于寄存器的旧值。
使用movdq2q mm0, xmm0movq2dq xmm0, mm0在XMM和MMX之间移动数据。
使用movaps xmm1, xmm0复制寄存器,即使数据仅在下半部分。(movsd xmm1, xmm0将低半部分合并到原始高半部分。movq xmm1, xmm0将高半部分置零。)
addpsmulps在上半部分为零时工作正常。(如果任何垃圾(在上半部分)产生非正规结果,它们可以减慢速度,因此更喜欢将上半部分保持为零)。有关指令集参考,请参阅http://felixcloutier.com/x86/(以及x86标记wiki中的其他链接)。
FP数据的任何混洗都可以在shufpspshufd的XMM寄存器中完成,而不是复制回MMX寄存器以使用任何MMX混洗。

相关问题