通过 X86-64 的地址位置设置 XMM 寄存器

Set XMM register via address location for X86-64

我在内存中的某个地址有一个浮点值,我想通过使用该地址将 XMM 寄存器设置为该值。我正在使用 asmjit.

此代码适用于 32 位构建 并将 XMM 寄存器 v 设置为正确的值 *f:

using namespace asmjit;
using namespace x86;

void setXmmVarViaAddressLocation(X86Compiler& cc, X86Xmm& v, const float* f)
{
   cc.movq(v, X86Mem(reinterpret_cast<std::uintptr_t>(f)));
}

但是,当我以 64 位编译时,我在尝试使用寄存器时遇到段错误。这是为什么?

(是的,我的组装能力不是很强...请客气...我已经用了一天了...)

最简单的解决方案是避免ptr()中的绝对地址。原因是 x86/x86_64 需要 32 位位移,这对于任意用户地址并不总是可能的 - 位移是通过使用当前指令指针和目标地址计算的 - 如果差异在带符号的 32-位整数指令不可编码(这是一个体系结构约束)。

示例代码:

using namespace asmjit;

void setXmmVarViaAddressLocation(x86::Compiler& cc, x86::Xmm& v, const float* f)
{
    x86::Gp tmpPtr = cc.newIntPtr("tmpPtr");
    cc.mov(tmpPtr, reinterpret_cast<std::uintptr_t>(f);
    cc.movq(v, x86::ptr(tmpPtr));
}

如果您想针对没有问题的 32 位模式优化此代码,则必须先检查目标体系结构,例如:

using namespace asmjit;

void setXmmVarViaAddressLocation(x86::Compiler& cc, x86::Xmm& v, const float* f)
{
    // Ideally, abstract this out so the code doesn't repeat.
    x86::Mem m;
    if (cc.is32Bit() || reinterpret_cast<std::uintptr_t>(f) <= 0xFFFFFFFFu) {
        m = x86::ptr(reinterpret_cast<std::uintptr_t>(f));
    }
    else {
        x86::Gp tmpPtr = cc.newIntPtr("tmpPtr");
        cc.mov(tmpPtr, reinterpret_cast<std::uintptr_t>(f);
        m = x86::ptr(tmpPtr);
    }

    // Do the move, now the content of `m` depends on target arch.
    cc.movq(v, x86::ptr(tmpPtr));
}

这样在32位模式下就省了一个寄存器,总是弥足珍贵