Nel famoso documento "Smashing Stack per divertimento e profitto", il suo autore prende una funzione Callineamento di memoria di oggi e 20 anni fa
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
e genera l'uscita codice assembly corrispondente
pushl %ebp
movl %esp,%ebp
subl $20,%esp
L'autore spiega che poiché i computer indirizzano la memoria in multipli di dimensione della parola, il compilatore ha riservato 20 byte nello stack (8 byte per il buffer1, 12 byte per il buffer2).
ho cercato di ricreare questo esempio e ha ottenuto la seguente
pushl %ebp
movl %esp, %ebp
subl $16, %esp
un risultato diverso! Ho provato varie combinazioni di dimensioni per buffer1 e buffer2, e sembra che il moderno gcc non riempia più le dimensioni del buffer in multipli di word size. Invece si abbandona l'opzione -mpreferred-stack-boundary
.
Come illustrazione - utilizzando le regole aritmetiche della carta, per buffer1 [5] e buffer2 [13] ottengo 8 + 16 = 24 byte riservati nello stack. Ma in realtà ho avuto 32 byte.
La carta è piuttosto vecchia e da allora sono successe molte cose. Mi piacerebbe sapere, cosa ha motivato esattamente questo cambiamento di comportamento? È la mossa verso le macchine a 64 bit? O qualcos'altro?
Modifica
Il codice è compilato su una macchina x86_64 usando gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) così:
$ gcc -S -o example1.s example1.c -fno-stack-protector -m32
8 + 16 è 24, non 20. A proposito, sembra probabile che il compilatore sia diventato un po 'più intelligente, il suo pass di analisi delle variabili locali ha preso in considerazione entrambi gli array di caratteri, e poiché gli array di caratteri non hanno bisogno di alcun allineamento, li ha semplicemente incollati e allineati alla matrice "compatta" risultante. –
C'è qualche punto nell'allineamento dei valori di 'char' in ogni caso? –
si trova su x86 o x86_64? – rmmh