简体   繁体   English

由于使用 SSE 指令的未对齐 memory 访问导致的一般保护异常

[英]General Protection Exception due to unaligned memory access with SSE instructions

There is a C structure of size 68 bytes, which is being passed as an argument to another function say Temp.有一个大小为 68 字节的 C 结构,它作为参数传递给另一个 function 说 Temp。

#pragma pack(1)
struct A {
    char [68];
};
#pragma pack()


void Temp(struct A)
{
/*
    some code goes here
*/
}

int main()
{
        struct A var1;

        Temp(var1); //-> SSE instructions are generated for this call (MOVAPS ...)

        return 0;
}

In the disassembled code(not for the above code, only the scenario is being illustrated), we see that the SSE(MOVAPS) instructions are being used prior to the function call(Temp).在反汇编代码中(不是上面的代码,只说明了场景),我们看到在 function 调用(Temp)之前使用了 SSE(MOVAPS)指令。 It appears that the memory operand for these instructions are unaligned which triggers General Protection Exception.这些指令的 memory 操作数似乎未对齐,这会触发一般保护异常。 The Optimization level used is /O1b2s.使用的优化级别是/O1b2s。 Please note that the issue is not seen with optimization disabled.请注意,禁用优化后不会出现此问题。 The source was originally being compiler with Visual Studio 2008 where this issue was not observed.源代码最初是使用 Visual Studio 2008 编译的,但未观察到此问题。 The compiler was upgraded to Visual Studio 2017 and the issued started surfacing.编译器升级到 Visual Studio 2017 并发布开始浮出水面。

The workarounds we have now are 1. using the /Ob2 as the compiler optimization level 2. using #pragma optimize(off) and #pragma optimize (on)我们现在的解决方法是 1. 使用 /Ob2 作为编译器优化级别 2. 使用 #pragma optimize(off) 和 #pragma optimize(on)

There are implications for both of the workarounds.这两种解决方法都有影响。 For the first workaround, the code size significantly goes up, but there is size constraint.对于第一个解决方法,代码大小显着增加,但存在大小限制。 We are still evaluating the consequences for the second workaround.我们仍在评估第二种解决方法的后果。

The scope of the code is in the UEFI environment.代码的scope是在UEFI环境下的。

Any suggestions to avoid this would be much appreciated.任何避免这种情况的建议将不胜感激。

This sounds like a compiler bug.这听起来像一个编译器错误。 However I have not been able to reproduce this issue with Visual Studio 2019 (16.3.9)但是我无法使用 Visual Studio 2019 (16.3.9) 重现此问题

This is the code I used:这是我使用的代码:

#include <stdio.h>

#pragma pack(1)
struct A {
    char field[68];
};
#pragma pack()


__declspec(noinline) void Temp(struct A a)
{
    if (a.field[3] != 0)
    {
        printf("hello world\n");
    }
}

int main()
{
    struct A var1 = {0};

    Temp(var1); //-> SSE instructions are generated for this call (MOVAPS ...)

    return 0;
}

The generated assembly is生成的程序集是

Temp(var1); //-> SSE instructions are generated for this call (MOVAPS ...)
00007FF710D510A4  movaps      xmmword ptr [rbp+7],xmm0  
00007FF710D510A8  movaps      xmm0,xmmword ptr [rbp-29h]  
00007FF710D510AC  movaps      xmmword ptr [rbp+17h],xmm1  
00007FF710D510B0  movaps      xmm1,xmmword ptr [rbp-19h]  
00007FF710D510B4  movaps      xmmword ptr [rbp+27h],xmm0  
00007FF710D510B8  movaps      xmmword ptr [rbp+37h],xmm1  
00007FF710D510BC  mov         dword ptr [rbp+47h],eax  
00007FF710D510BF  call        Temp (07FF710D5105Ch)

I count 4 MOVAPS and one MOV DWORD.我数了 4 MOVAPS 和 1 MOV DWORD。 This seems to match the 68 bytes size you've specified.这似乎与您指定的 68 字节大小相匹配。

If this is a bug in VS2017 that has been fixed in VS2019, then I'd suggest you move to the new compiler.如果这是已在 VS2019 中修复的 VS2017 中的错误,那么我建议您转移到新的编译器。 Especially that it is ABI compatible with VS2017.特别是它与 VS2017 兼容的 ABI。 Try it?试试看?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM