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



我在内存中的某个地址有一个浮点值,我想使用该地址将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位编译时,在尝试使用寄存器时会出现segfault。为什么?

(是的,我在组装方面不是很强……请善良……我已经做了一天了……(

最简单的解决方案是避免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位模式下保存一个寄存器,这总是很宝贵的。

最新更新