Strano assembly dall'inizializzazione dell'array 0

Strano assembly dall'inizializzazione dell'array 0


Ispirato dalla domanda Differenza nell'inizializzazione e nell'azzeramento di un array in c/c++?, ho deciso di esaminare effettivamente l'assemblaggio di, nel mio caso, una build di rilascio ottimizzata per Windows Mobile Professional (processore ARM, dal compilatore di ottimizzazione Microsoft). Quello che ho trovato è stato in qualche modo sorprendente e mi chiedo se qualcuno può fare luce sulle mie domande a riguardo.


Vengono esaminati questi due esempi:


byte a[10] = { 0 };
byte b[10];
memset(b, 0, sizeof(b));

Sono usati nella stessa funzione, quindi lo stack appare così:


[ ] // padding byte to reach DWORD boundary
[ ] // padding byte to reach DWORD boundary
[ ] // b[9] (last element of b)
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ] // b[0] = sp + 12 (stack pointer + 12 bytes)
[ ] // padding byte to reach DWORD boundary
[ ] // padding byte to reach DWORD boundary
[ ] // a[9] (last element of a)
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ] // a[0] = sp (stack pointer, at bottom)

L'assembly generato con i miei commenti:


; byte a[10] = { 0 };
01: mov r3, #0 // r3 = 0
02: mov r2, #9 // 3rd arg to memset: 9 bytes, note that sizeof(a) = 10
03: mov r1, #0 // 2nd arg to memset: 0-initializer
04: add r0, sp, #1 // 1st arg to memset: &a[1] = a + 1, since only 9 bytes will be set
05: strb r3, [sp] // a[0] = r3 = 0, sets the first element of a
06: bl memset // continue in memset
; byte b[10];
; memset(b, 0, sizeof(b));
07: mov r2, #0xA // 3rd arg to memset: 10 bytes, sizeof(b)
08: mov r1, #0 // 2nd arg to memset: 0-initializer
09: add r0, sp, #0xC // 1st arg to memset: sp + 12 bytes (the 10 elements
// of a + 2 padding bytes for alignment) = &b[0]
10: bl memset // continue in memset

Ora, ci sono due cose che mi confondono:



  1. Qual ​​è il punto delle righe 02 e 05? Perché non dare semplicemente &a[0] e 10 byte a memset?

  2. Perché i byte di riempimento di uno 0 non sono inizializzati? È solo per il riempimento negli struct?


Modifica:ero troppo curioso per non testare lo struct case:


struct Padded
{
DWORD x;
byte y;
};

L'assembler per inizializzarlo 0:


; Padded p1 = { 0 };
01: mov r3, #0
02: str r3, [sp]
03: mov r3, #0
04: str r3, [sp, #4]
; Padded p2;
; memset(&p2, 0, sizeof(p2));
05: mov r3, #0
06: str r3, [sp]
07: andcs r4, r0, #0xFF
08: str r3, [sp, #4]

Qui vediamo nella riga 04 che si verifica effettivamente un padding, poiché str (al contrario di strb ) viene usato. Giusto?


Alcune risposte al codice


byte a[10] = { 0 };
byte b[10];
memset(b, 0, sizeof(b));
[ ] // padding byte to reach DWORD boundary [ ] // padding byte to reach DWORD boundary [ ] // b[9] (last element of b) [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] // b[0] = sp + 12 (stack pointer + 12 bytes) [ ] // padding byte to reach DWORD boundary [ ] // padding byte to reach DWORD boundary [ ] // a[9] (last element of a) [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] // a[0] = sp (stack pointer, at bottom) 
;
byte a[10] = { 0 };
01: mov r3, #0
// r3 = 0 02: mov r2, #9
// 3rd arg to memset: 9 bytes, note that sizeof(a) = 10 03: mov r1, #0
// 2nd arg to memset: 0-initializer 04: add r0, sp, #1 // 1st arg to memset: &a[1] = a + 1, since only 9 bytes will be set 05: strb r3, [sp]
// a[0] = r3 = 0, sets the first element of a 06: bl memset
// continue in memset ;
byte b[10];
;
memset(b, 0, sizeof(b));
07: mov r2, #0xA
// 3rd arg to memset: 10 bytes, sizeof(b) 08: mov r1, #0
// 2nd arg to memset: 0-initializer 09: add r0, sp, #0xC // 1st arg to memset: sp + 12 bytes (the 10 elements // of a + 2 padding bytes for alignment) = &b[0] 10: bl memset
// continue in memset
struct Padded {
DWORD x;
byte y;
};
;
Padded p1 = { 0 };
01: mov r3, #0 02: str r3, [sp] 03: mov r3, #0 04: str r3, [sp, #4] ;
Padded p2;
;
memset(&p2, 0, sizeof(p2));
05: mov r3, #0 06: str r3, [sp] 07: andcs r4, r0, #0xFF 08: str r3, [sp, #4]
byte a[10] = { };
;
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

No