简体   繁体   中英

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.

#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). It appears that the memory operand for these instructions are unaligned which triggers General Protection Exception. The Optimization level used is /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. The compiler was upgraded to Visual Studio 2017 and the issued started surfacing.

The workarounds we have now are 1. using the /Ob2 as the compiler optimization level 2. using #pragma optimize(off) and #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.

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)

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. This seems to match the 68 bytes size you've specified.

If this is a bug in VS2017 that has been fixed in VS2019, then I'd suggest you move to the new compiler. Especially that it is ABI compatible with VS2017. Try it?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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