MOVAPS访问未对齐的地址

时间:2016-03-02 23:03:26

标签: c++ visual-studio-2013 sse memory-alignment disassembly

由于某种原因,我的一个函数是使用未对齐的参数调用SSE指令movaps,这会导致崩溃。它发生在函数的第一行,其余部分只需要在那里发生崩溃,但是为了清晰起见,这是遗漏的。

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)));

    // ...
}

这是我从调试主程序中调用它的方式:

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;
}

这是从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  

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

你认为这种行为有什么原因吗?

其他信息

我上传的small compilable example在我的Visual Studio中崩溃了,但在IDEone中没有。

代码在Visual Studio 2013 Update 5(x64发行版,v120)中编译。我已经设置了" Struct Member Alignment"将项目设置为16个字节,但几乎没有改进,并且我使用的结构中没有打包pragma。错误消息是:

  

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

1 个答案:

答案 0 :(得分:2)

gcc和clang都很好,并为您的示例制作非崩溃的非矢量化代码。 (当然,我正在为Linux SysV ABI编译,其中没有一个向量寄存器被调用者保存,所以他们没有生成代码来在第一个栈中保存xmm {6..15}的地方。)

你的IDEone链接也没有显示崩溃,所以IDK。我有在线编译&运行具有MSVC作为选项的站点。如果您的程序使用system来运行反汇编程序,您甚至可以从中获取asm。 :P

您发布的asm输出保证崩溃,因为任何可能的rax值:

00007FF7A7DC3522  movaps      xmmword ptr [rax-58h],xmm10  
00007FF7A7DC3527  lea         rax,[rax+18h]  
...
00007FF7A7DC3533  movaps      xmmword ptr [rax-68h],xmm11

考虑到LEA,第二个商店地址是[init_rax-50h],它与早期商店的偏移量仅为8B。一个或另一个会出错。 这似乎是您应该报告的编译器错误。

我不知道为什么你的编译器会使用lea而不是add rax, 18h。它在使用comiss

打破标志之前就做到了