Condividi tramite


Uso dello stack x64

Tutta la memoria oltre l'indirizzo corrente di RSP è considerata volatile: il sistema operativo o un debugger può sovrascrivere questa memoria durante una sessione di debug dell'utente o un gestore di interrupt. Pertanto, RSP deve essere sempre impostato prima di tentare di leggere o scrivere valori in uno stack frame.

Questa sezione illustra l'allocazione dello spazio dello stack per le variabili locali e l'intrinseco alloca .

Allocazione nello stack

Il prologo di una funzione è responsabile dell'allocazione dello spazio dello stack per le variabili locali, i registri salvati, i parametri dello stack e i parametri di registrazione.

L'area del parametro si trova sempre nella parte inferiore dello stack (anche se alloca viene usata), in modo che sia sempre adiacente all'indirizzo restituito durante qualsiasi chiamata di funzione. Contiene almeno quattro voci, ma sempre sufficiente spazio per contenere tutti i parametri necessari per qualsiasi funzione che può essere chiamata. Si noti che lo spazio viene sempre allocato per i parametri del registro, anche se i parametri stessi non sono mai ospitati nello stack; Un chiamato garantisce che lo spazio sia stato allocato per tutti i relativi parametri. Gli indirizzi home sono necessari per gli argomenti del registro in modo che sia disponibile un'area contigua nel caso in cui la funzione chiamata debba accettare l'indirizzo dell'elenco di argomenti (va_list) o un singolo argomento. Questa area offre anche un'area comoda per salvare gli argomenti di registrazione durante l'esecuzione del thunk e come opzione di debug (ad esempio, rende gli argomenti facili da trovare durante il debug se sono archiviati nei rispettivi indirizzi di casa nel codice prologo). Anche se la funzione chiamata ha meno di 4 parametri, queste 4 posizioni dello stack sono effettivamente di proprietà della funzione chiamata e possono essere usate dalla funzione chiamata per altri scopi oltre a salvare i valori del registro dei parametri. Di conseguenza, il chiamante potrebbe non salvare informazioni in questa area dello stack in una chiamata di funzione.

Se lo spazio viene allocato dinamicamente (alloca) in una funzione, è necessario usare un registro non volatile come puntatore a fotogramma per contrassegnare la base della parte fissa dello stack e tale registro deve essere salvato e inizializzato nel prologo. Si noti che quando alloca viene usato, le chiamate allo stesso chiamato dallo stesso chiamante possono avere indirizzi di casa diversi per i relativi parametri di registrazione.

Lo stack verrà sempre allineato a 16 byte, tranne all'interno del prologo (ad esempio, dopo il push dell'indirizzo restituito) e tranne dove indicato in Tipi di funzione per una determinata classe di funzioni frame.

Di seguito è riportato un esempio del layout dello stack in cui la funzione A chiama una funzione non foglia B. Il prologo della funzione A ha già allocato spazio per tutti i parametri di registro e stack richiesti da B nella parte inferiore dello stack. La chiamata esegue il push dell'indirizzo restituito e il prologo di B alloca spazio per le variabili locali, i registri nonvolatili e lo spazio necessario per chiamare le funzioni. Se B usa alloca, lo spazio viene allocato tra l'area di salvataggio del registro variabile locale/non volatile e l'area dello stack di parametri.

Diagramma del layout dello stack per l'esempio di conversione x64.

Quando la funzione B chiama un'altra funzione, viene eseguito il push dell'indirizzo restituito appena sotto l'indirizzo home per RCX.

Costruzione dinamica dell'area dello stack di parametri

Se viene usato un puntatore a frame, l'opzione esiste per creare dinamicamente l'area dello stack di parametri. Questa operazione non viene attualmente eseguita nel compilatore x64.

Tipi di funzione

Esistono fondamentalmente due tipi di funzioni. Una funzione che richiede uno stack frame è detta funzione frame. Una funzione che non richiede uno stack frame è detta funzione foglia.

Una funzione frame è una funzione che alloca lo spazio dello stack, chiama altre funzioni, salva registri non volatile o usa la gestione delle eccezioni. Richiede anche una voce di tabella della funzione. Una funzione frame richiede un prologo e un epilogo. Una funzione frame può allocare dinamicamente lo spazio dello stack e può usare un puntatore a fotogrammi. Una funzione frame ha le funzionalità complete di questo standard chiamante a sua disposizione.

Se una funzione frame non chiama un'altra funzione, non è necessario allineare lo stack (a cui si fa riferimento in Allocazione stack di sezioni).

Una funzione foglia è una che non richiede una voce della tabella di funzioni. Non può apportare modifiche a registri non volatile, incluso RSP, il che significa che non può chiamare alcuna funzione o allocare spazio dello stack. È consentito lasciare lo stack non allineato durante l'esecuzione.

allineamento malloc

Malloc è garantito di restituire memoria allineata in modo adeguato per l'archiviazione di qualsiasi oggetto con un allineamento fondamentale e che potrebbe rientrare nella quantità di memoria allocata. Un allineamento fondamentale è un allineamento minore o uguale all'allineamento più grande supportato dall'implementazione senza una specifica di allineamento. In Visual C++, questo è l'allineamento necessario per un doubleo 8 byte. Nel codice destinato a piattaforme a 64 bit, si tratta di 16 byte. Ad esempio, un'allocazione a quattro byte viene allineata su un limite che supporta qualsiasi oggetto a quattro byte o più piccolo.

Visual C++ consente tipi con allineamento esteso, noti anche come tipi sovraallineare . Ad esempio, i tipi SSE __m128 e , __m256e i tipi dichiarati tramite dove __declspec(align( n )) n è maggiore di 8, hanno un allineamento esteso. L'allineamento della memoria su un limite adatto per un oggetto che richiede l'allineamento esteso non è garantito da malloc. Per allocare memoria per i tipi sovraallineare, usare _aligned_malloc e funzioni correlate.

alloca

_alloca deve essere allineato a 16 byte e deve inoltre usare un puntatore a fotogramma.

Lo stack allocato deve includere spazio dopo di esso per i parametri delle funzioni chiamate successivamente, come descritto in Allocazione stack.

Vedi anche

Convenzioni del software x64
align
__declspec