Non c'è alcun obbligo di utilizzare uno stack frame, ma ci sono sicuramente alcuni vantaggi:
In primo luogo , se ogni funzione ha utilizzato questo stesso processo, possiamo usare questa conoscenza per determinare facilmente una sequenza di chiamate (lo stack di chiamate) invertendo il processo. Sappiamo che dopo un'istruzione call
, ESP
punti per l'indirizzo di ritorno e che la prima cosa che la funzione chiamata farà è push
l'attuale EBP
e quindi copiare ESP
in EBP
. Quindi, in qualsiasi momento possiamo guardare i dati indicati da EBP
che sarà il precedente EBP
e che EBP+4
sarà l'indirizzo di ritorno dell'ultima chiamata di funzione. Possiamo quindi stampare il (32bit assumendo) stack di chiamate utilizzando qualcosa di simile (scusate il arrugginita C++):
void LogStack(DWORD ebp)
{
DWORD prevEBP = *((DWORD*)ebp);
DWORD retAddr = *((DWORD*)(ebp+4));
if (retAddr == 0) return;
HMODULE module;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*)retAddr, &module);
char* fileName = new char[256];
fileName[255] = 0;
GetModuleFileNameA(module, fileName, 255);
printf("0x%08x: %s\n", retAddr, fileName);
delete [] fileName;
if (prevEBP != 0) LogStack(prevEBP);
}
Questo sarà quindi stampare l'intera sequenza di chiamate (o meglio, i loro indirizzi di ritorno) fino a quel momento.
Inoltre, dal momento che EBP
non cambia a meno che non si aggiorna in modo esplicito che (a differenza di ESP
, che cambia quando si push
/pop
), di solito è più facile fare riferimento i dati nello stack rispetto al EBP
, piuttosto che rispetto al ESP
, dal momento che con quest'ultimo, è necessario essere a conoscenza di tutte le istruzioni push
/pop
che potrebbero essere state chiamate tra l'inizio della funzione e il riferimento.
Come altri hanno detto, si dovrebbe evitare di utilizzare pila indirizzi sottoESP
come qualsiasi call
s fate ad altre funzioni sono suscettibili di sovrascrivere i dati a questi indirizzi.Si dovrebbe invece riservare spazio sullo stack per l'utilizzo da parte vostra funzione dal solito:
sub esp, [number of bytes to reserve]
Dopo questo, la regione dello stack tra il primo e ESP
ESP - [number of bytes reserved]
è sicuro da usare. Prima di uscire la funzione è necessario liberare lo spazio di stack riservato utilizzando una corrispondenza:
add esp, [number of bytes reserved]
Questa tecnica ha un nome: _frame puntatore optimization_. – legends2k
possibile duplicato di [Qual è lo scopo del registro del puntatore del frame EBP?] (Http://stackoverflow.com/questions/579262/what-is-the-purpose-of-the-ebp-frame-pointer-register) –