Strange assembly from array 0-initialization

前端 未结 3 537
清酒与你
清酒与你 2020-12-13 19:10

Inspired by the question Difference in initalizing and zeroing an array in c/c++ ?, I decided to actually examine the assembly of, in my case, an optimized release build for

相关标签:
3条回答
  • 2020-12-13 19:34

    Both bits of code are bugfree. The two lines mentioned aren't smart, but you're just proving that this compiler is emitting suboptimal code.

    Padding bytes are usually only initialized if that simplifies the assembly or speeds up the code. E.g if you have padding between two zero-filled members, it's often easier to zero-fill the padding as well. Also, if you have padding at the end and your memset() is optimized for multi-byte writes, it may be faster to overwrite that padding too.

    0 讨论(0)
  • 2020-12-13 19:36

    Some quick testing indicates that Microsoft's x86 compiler generates different assembly if the initializer list is empty, compared to when it contains a zero. Maybe their ARM compiler does too. What happens if you do this?

    byte a[10] = { };
    

    Here's the assembly listing I got (with options /EHsc /FAs /O2 on Visual Studio 2008). Note that including a zero in the initializer list causes the compiler to use unaligned memory accesses to initialize the array, while the empty initializer list version and the memset() version both use aligned memory accesses:

    ; unsigned char a[10] = { };
    
    xor eax, eax
    mov DWORD PTR _a$[esp+40], eax
    mov DWORD PTR _a$[esp+44], eax
    mov WORD PTR _a$[esp+48], ax
    
    ; unsigned char b[10] = { 0 };
    
    mov BYTE PTR _b$[esp+40], al
    mov DWORD PTR _b$[esp+41], eax
    mov DWORD PTR _b$[esp+45], eax
    mov BYTE PTR _b$[esp+49], al
    
    ; unsigned char c[10];
    ; memset(c, 0, sizeof(c));
    
    mov DWORD PTR _c$[esp+40], eax
    mov DWORD PTR _c$[esp+44], eax
    mov WORD PTR _c$[esp+48], ax
    
    0 讨论(0)
  • 2020-12-13 19:41

    The reason for lines 2 and 5 is because you specified a 0 in the array initializer. The compiler will initialize all constants then pad out the rest using memset. If you were to put two zeros in your initializer, you'd see it strw (word instead of byte) then memset 8 bytes.

    As for the padding, it's only used to align memory accesses -- the data shouldn't be used under normal circumstances, so memsetting it is wasteful.

    Edit: For the record, I may be wrong about the strw assumption above. 99% of my ARM experience is reversing code generated by GCC/LLVM on the iPhone, so my assumption may not carry over to MSVC.

    0 讨论(0)
提交回复
热议问题