// Titolo: Stack in azione v0.2
// Autore: Saio
// Data: Marzo 2005

////////////
// PAG.01 //
////////////


-----------------------------
INDICE PAG.01 PAG.02 PAG.03 PAG.04
-----------------------------

///////COME RAGIONA LO STACK////////

//Analizziamo il seguente programmino in C

----------inizio voordeeld1.c---------
void function (int a, int b, int c){
char buffer1[5];
char buffer2[10];
}
int main(void) {
function(1, 2, 3);
return 0;
}
---------fine voordeeld1.c---------


// Compilo con gcc e poi disassemblo con gdb prima il main e poi function
[root@localhost twan]# gcc -static voorbeeld1.c -o voorbeeld1
[root@localhost twan]# gdb voorbeeld1
(gdb) disassemble main
...
(gdb) disassemble function
...

// Dai dati ottenuti, che potete trovare per intero qui,
// valuto come effettivamente varia lo stack
---------------------
LEGENDA:
/* = Break, info register
*/ = Continue
// = Commenti
---------------------

// La situazione iniziale e' quella di Fig.01, poi in Fig.02 si mette in evidenza
// il prologo della funzione main: l’indirizzo che e’ in ebp viene inserito nello
// stack, poi l’indirizzo di esp viene copiato all’interno di ebp, per cui ora
// ebp e esp hanno lo stesso indirizzo: f988.(Fig.02B)

...eip..../*.....esp......ebp......*/

....||............||.......||......
....||............||.......||......
...\||/..........\||/.....\||/.....
....\/............\/.......\/......

0x80481f0 /* 0xbffff98c 0xbffff9c8 */ <main>: push %ebp


0x80481f1
/* 0xbffff988 0xbffff9c8 */ <main+1>: mov %esp,%ebp


0x80481f3 /* 0xbffff988 0xbffff988 */ <main+3>: sub $0x8,%esp


0x80481f6
/* 0xbffff980 0xbffff988 */ <main+6>: sub $0x4,%esp


0x80481f9
/* 0xbffff97c 0xbffff988 */ <main+9>: push $0x3
0x80481fb
/* 0xbffff978 0xbffff988 */ <main+11>: push $0x2
0x80481fd
/* 0xbffff974 0xbffff988 */ <main+13>: push $0x1


0x80481ff
/* 0xbffff970 0xbffff988 */ <main+15>: call 0x80481e0 <function>

// Viene chiamata la function, quindi si ha l’avvio di una nuova procedura di prologo
// per spostare EBP all’inizio della parte di stack dedicata alla function. Quando si
// chiama la ‘call’ sullo stack si crea un RET che contiene l’indirizzo di ritorno
// in modo che finita la function si possa ripartire ESATTAMENTE dall’istruzione
// successiva alla ‘call’, che nel nostro caso e’ 0x8048204, tale indirizzo e’
// percio’ situato all’interno del RET. Quindi RET viene pushato sullo stack (Fig.06)

0x80481e0 /* 0xbffff96c 0xbffff988 */ <function>: push %ebp

// Qui avviene la push di ebp, che servira’ una volta conclusa la function per tornare
// alla ebp del main (Fig.07).


0x80481e1 /* 0xbffff968 0xbffff988 */ <function+1>: mov %esp,%ebp


0x80481e3 /* 0xbffff968 0xbffff968 */ <function+3>: sub $0x28,%esp


0x80481e6 /* 0xbffff940 0xbffff968 */ <function+6>: mov %ebp,%esp


0x80481e8 /* 0xbffff968 0xbffff968 */ <function+8>: pop %ebp


0x80481e9
/* 0xbffff96c 0xbffff988 */ <function+9>: ret


0x80481ea
<function+10>: lea 0x0(%esi),%esi
// Si ritorna al main
0x8048204 /* 0xbffff970 0xbffff988 */ <main+20>: add $0x10,%esp


0x8048207 /* 0xbffff980 0xbffff988 */ <main+23>: mov $0x0,%eax
0x804820c
/* 0xbffff980 0xbffff988 */ <main+28>: mov %ebp,%esp


0x804820e
/* 0xbffff988 0xbffff988 */ <main+30>: pop %ebp


0x804820f
/* 0xbffff98c 0xbffff9c8 */ <main+31>: ret
End of assembler dump.
(gdb) q


// N.B. E’ stato sovrapposto il disassemblato di function al main in maniera
// artificiosa per chiarire meglio come varia lo stack.
// Se ci sono errori, essi non sono voluti,
// pertanto sono gradite segnalazioni a riguardo.

///////Note aggiuntive////////
// Nell'esempio preso in considerazione:
void function (int a, int b, int c){
char buffer1[5];
char buffer2[10];
}
int main(void) {
function(1, 2, 3);
return 0;
}
// la function viene chiamata dal main, lo stack crea lo spazio in cui
// andra' ad allocare buffer1[5] e buffer2[10]
// Lo spazio S puo' viene calcolato con questa regolina, verificabile disassemblando
// function.
/////////////////////////////////////////////////////////////////////////////
//
// S = (8) + [16,32,48,...] + [16,32,48,...] + [16,32,48,...] + [16,32,48,...] + ....
//
/////////////////////////////////////////////////////////////////////////////
// in cui il buffer1[5] occupa 16 byte
// in cui il buffer2[10] occupa 16 byte
// => (8) + [16] + [16] = 40 byte = 0x28 in esadecimale,
// come si vede dal disassemblato della function:

0x80481e3 <function+3>: sub $0x28,%esp

// Nel caso in cui vi sia un buffer1[16] e un buffer2[17]
// lo stack si sposta di 56 byte = 0x38 in esadecimale seguendo la regola per cui
// il buffer1[16] occupa 16 byte
// il buffer2[17] occupa 32 byte
// => (8) + [16] + [32] = 56 byte

// Nel caso in cui vi sia un buffer1[135], un buffer2[173] e un buffer3[37]
void function (int a, int b, int c){
char buffer1[135];
char buffer2[173];
char buffer3[37];
}
int main(void) {
function(1, 2, 3);
return 0;
}
// lo stack viene occupato da 376 byte seguendo la regola per cui
// il buffer1[135] occupa 144 byte
// il buffer2[173] occupa 176 byte
// il buffer3[37] occupa 48 byte
// => [144] + [176] + [48] + (8) = 376 byte = 0x178 in esadecimale
// per verificarlo basta disassemblare con gdb e verificare che nella function
// sia indicata l'istruzione 'sub $0x178,%esp'
// Proviamo...
[root@localhost imparo]# gcc -static prova.c -o prova
[root@localhost imparo]# gdb prova
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-mandrake-linux"...
(gdb) disassemble function
Dump of assembler code for function function:
0x80481e0 <function>: push %ebp
0x80481e1 <function+1>: mov %esp,%ebp
0x80481e3 <function+3>: sub $0x178,%esp <======= ECCO QUI, COME VOLEVAMO DIMOSTRARE!!
0x80481e9 <function+9>: mov %ebp,%esp
0x80481eb <function+11>: pop %ebp
0x80481ec <function+12>: ret
0x80481ed <function+13>: lea 0x0(%esi),%esi
End of assembler dump.
(gdb)q

// Analizzeremo meglio questa regola a pag.4 che comprende delle eccezioni:
// come buffer[1], buffer[2], buffer[4], buffer[8], i quali soddisfano
// criteri diversi e hanno proprieta' di legamento (LEG1, LEG2) e appoggi
// a destra (APDX) all'interno dello stack.



-----------------------------
INDICE PAG.01 PAG.02 PAG.03 PAG.04
-----------------------------