Visual Studio和Unity Mono注册clobbering

时间:2018-03-02 17:41:04

标签: mono 64-bit pinvoke cpu-registers

根据Saving the XMM register before function call,似乎XMM6到XMM15需要通过Windows上的函数调用来保留,但不需要在Linux上保留。

我有一个由Visual Studio 2015编译的本机插件,用于使用Mono的Unity。 C#代码将委托传递给本机插件,该插件接收它作为函数指针(为了32位构建而注释stdcall,尽管我遇到的问题是64位的)。因此,这意味着本机代码可以调用由Mono实现的函数。

当我这样做时,单声道功能似乎正在破坏XMM6到XMM15。 Visual Studio编译的代码显然没有预料到这一点,并且会出现故障。

有什么方法可以解决这个问题吗?是否可以注释特定的函数指针,以便Microsoft知道它们的行为是错误的?我们可以调用内在函数来保存和恢复那些我们知道有这个问题的调用吗?其他想法?

进一步发现进行编辑:

寄存器仅在第一次调用给定的C#函数时被破坏。我已将它追溯到Mono AMD64普通蹦床。 This commit修复了这个错误,但是Unity使用的旧版Mono仍然拥有它。错误是XMM0到XMM7是使用MOVSD保存和恢复的,pegjs.org只保存低64位并将高64位重置为0,而XMM8到XMM15根本没有保存,这可能很重要使用它们。

1 个答案:

答案 0 :(得分:0)

这似乎适用于简单的情况:

#include <immintrin.h>

alignas(16) std::array<uint8_t, 512> regs;
_fxsave64(regs.data());
callToMonoGoesHere();
_fxrstor64(regs.data());

如果函数返回浮点值,则必须执行额外的步骤:

alignas(16) std::array<uint8_t, 512> before, after;
_fxsave64(before.data());
float f = callToMonoGoesHere();
_fxsave64(after.data());
memcpy(after.data() + 256, before.data() + 256, 160); //XMM6 to 15
_fxrstor64(after.data());
相关问题