MOVAPS 访问未对齐的地址

ivo*_*bel 5 c++ sse memory-alignment disassembly visual-studio-2013

出于某种原因,我的一个函数正在调用movaps带有未对齐参数的 SSE 指令,这会导致崩溃。它发生在函数的第一行,其余的都需要在那里发生崩溃,但为了清楚起见省略了。

Vec3f CrashFoo(
    const Vec3f &aVec3,
    const float  aFloat,
    const Vec2f &aVec2)
{
    const Vec3f vecNew =
        Normalize(Vec3f(aVec3.x, aVec3.x, std::max(aVec3.x, 0.0f)));

    // ...
}
Run Code Online (Sandbox Code Playgroud)

这是我从调试主要调用它的方式:

int32_t main(int32_t argc, const char *argv[])
{
    Vec3f vec3{ 0.00628005248f, -0.999814332f, 0.0182171166f };
    Vec2f vec2{ 0.947231591f, 0.0522233732f };
    float floatVal{ 0.010f };

    Vec3f vecResult = CrashFoo(vec3, floatVal, vec2);

    return (int32_t)vecResult.x;
}
Run Code Online (Sandbox Code Playgroud)

这是从CrashFoo函数开头到崩溃行的反汇编:

00007FF7A7DC34F0  mov         rax,rsp  
00007FF7A7DC34F3  mov         qword ptr [rax+10h],rbx  
00007FF7A7DC34F7  push        rdi  
00007FF7A7DC34F8  sub         rsp,80h  
00007FF7A7DC34FF  movaps      xmmword ptr [rax-18h],xmm6  
00007FF7A7DC3503  movss       xmm6,dword ptr [rdx]  
00007FF7A7DC3507  movaps      xmmword ptr [rax-28h],xmm7  
00007FF7A7DC350B  mov         dword ptr [rax+18h],0  
00007FF7A7DC3512  mov         rdi,r9  
00007FF7A7DC3515  mov         rbx,rcx  
00007FF7A7DC3518  movaps      xmmword ptr [rax-38h],xmm8  
00007FF7A7DC351D  movaps      xmmword ptr [rax-48h],xmm9  
00007FF7A7DC3522  movaps      xmmword ptr [rax-58h],xmm10  
00007FF7A7DC3527  lea         rax,[rax+18h]  
00007FF7A7DC352B  xorps       xmm8,xmm8  
00007FF7A7DC352F  comiss      xmm8,xmm6  
00007FF7A7DC3533  movaps      xmmword ptr [rax-68h],xmm11  
Run Code Online (Sandbox Code Playgroud)

我的理解是,它首先执行通常的函数调用,然后通过将某些 SSE 寄存器 ( xmm6- xmm11)的当前内容保存到堆栈中来开始准备操场,以便后续代码可以自由使用它们。该xmm*寄存器存储陆续地址中的一个从[rax-18h][rax-68h],这因为是很好对齐为16个字节rax=0xe4d987f788,但之前xmm11寄存器被存储时,rax增加18小时打破了对准引起崩溃。的xorpscomiss线是实际代码开始(std::max的与0比较)。当我删除std::max它时效果很好。

你看到这种行为的任何原因吗?

附加信息

我上传了一个小的可编译示例,它在我的 Visual Studio 中崩溃了,但在 IDEone 中没有。

代码在 Visual Studio 2013 Update 5(x64 版本,v120)中编译。我已将项目的“结构成员对齐”设置设置为 16 字节,但几乎没有改进,并且pragma我使用的结构中没有打包。错误信息是:

PG3Render.exe 中 0x00007ff7a7dc3533 处的第一次机会异常:0xC0000005:访问冲突读取位置 0xffffffffffffffff。

Pet*_*des 3

gcc 和 clang 都很好,可以为您的示例制作非崩溃的非矢量化代码。(当然,我正在针对 Linux SysV ABI 进行编译,其中没有调用者保存矢量寄存器,因此它们首先不会生成将 xmm{6..15} 保存在堆栈上的代码。)

您的 IDEone 链接也没有显示崩溃,所以 IDK。我有一些在线编译和运行站点,其中有 MSVC 作为选项。system如果您的程序用于自行运行反汇编程序,您甚至可以从中获取汇编语言。:P


对于任何可能的值,您发布的 asm 输出肯定rax会崩溃:

00007FF7A7DC3522  movaps      xmmword ptr [rax-58h],xmm10  
00007FF7A7DC3527  lea         rax,[rax+18h]  
...
00007FF7A7DC3533  movaps      xmmword ptr [rax-68h],xmm11
Run Code Online (Sandbox Code Playgroud)

考虑到 LEA,第二个存储地址是[init_rax-50h],它与之前的存储仅偏移 8B。其中之一将会出错。 这似乎是您应该报告的编译器错误。

我不知道为什么你的编译器会使用lea而不是add rax, 18h. 它在用 a 破坏标志之前执行此操作comiss