Utilisation de la pile x64
Toute la mémoire au-delà de l’adresse actuelle du RSP est considérée comme volatile : le système d’exploitation, ou un débogueur, peut remplacer cette mémoire pendant une session de débogage utilisateur ou un gestionnaire d’interruptions. Par conséquent, le RSP doit toujours être défini avant de tenter de lire ou d’écrire des valeurs dans une trame de pile.
Cette section décrit l’allocation d’espace de pile pour les variables locales et l’intrinsèque alloca .
Allocation de piles
Le prologue d’une fonction est chargé d’allouer de l’espace de pile pour les variables locales, les registres enregistrés, les paramètres de pile et les paramètres d’inscription.
La zone de paramètre est toujours au bas de la pile (même si alloca
elle est utilisée), afin qu’elle soit toujours adjacente à l’adresse de retour pendant tout appel de fonction. Il contient au moins quatre entrées, mais toujours suffisamment d’espace pour contenir tous les paramètres nécessaires par n’importe quelle fonction qui peut être appelée. Notez que l’espace est toujours alloué pour les paramètres de registre, même si les paramètres eux-mêmes ne sont jamais hébergés dans la pile ; un appelé est garanti que l’espace a été alloué pour tous ses paramètres. Les adresses d’accueil sont requises pour les arguments de registre afin qu’une zone contiguë soit disponible si la fonction appelée doit prendre l’adresse de la liste d’arguments (va_list) ou d’un argument individuel. Cette zone fournit également un emplacement pratique pour enregistrer les arguments d’inscription pendant l’exécution de thunk et en tant qu’option de débogage (par exemple, il facilite la recherche des arguments lors du débogage s’ils sont stockés à leurs adresses d’accueil dans le code de prolog). Même si la fonction appelée a moins de 4 paramètres, ces 4 emplacements de pile appartiennent effectivement à la fonction appelée et peuvent être utilisés par la fonction appelée à d’autres fins, en plus de l’enregistrement des valeurs de registre de paramètres. Ainsi, l’appelant peut ne pas enregistrer d’informations dans cette région de pile sur un appel de fonction.
Si l’espace est alloué dynamiquement (alloca
) dans une fonction, un registre nonvolatile doit être utilisé comme pointeur d’image pour marquer la base de la partie fixe de la pile et ce registre doit être enregistré et initialisé dans le prolog. Notez qu’en cas alloca
d’utilisation, les appels au même appelé à partir du même appelant peuvent avoir des adresses d’accueil différentes pour leurs paramètres d’inscription.
La pile est toujours maintenue alignée sur 16 octets, sauf dans le prologue (par exemple, une fois l’adresse renvoyée envoyée), et sauf si elle est indiquée dans les types de fonctions pour une certaine classe de fonctions frame.
Voici un exemple de disposition de pile où la fonction A appelle une fonction non feuille B. Le prolog de la fonction A a déjà alloué de l’espace pour tous les paramètres d’inscription et de pile requis par B en bas de la pile. L’appel envoie (push) l’adresse de retour et le prolog de B alloue de l’espace pour ses variables locales, ses registres nonvolatiles et l’espace nécessaire pour appeler des fonctions. Si B utilise alloca
, l’espace est alloué entre la variable locale/la zone d’enregistrement nonvolatile du registre et la zone de pile de paramètres.
Lorsque la fonction B appelle une autre fonction, l’adresse de retour est envoyée juste en dessous de l’adresse d’accueil pour RCX.
Construction de la zone de pile de paramètres dynamiques
Si un pointeur d’image est utilisé, l’option existe pour créer dynamiquement la zone de pile de paramètres. Cette opération n’est pas effectuée actuellement dans le compilateur x64.
Types de fonctions
Il existe essentiellement deux types de fonctions. Une fonction qui nécessite une trame de pile est appelée fonction frame. Une fonction qui ne nécessite pas d’image de pile est appelée fonction feuille.
Une fonction frame est une fonction qui alloue de l’espace de pile, appelle d’autres fonctions, enregistre des registres nonvolatiles ou utilise la gestion des exceptions. Elle nécessite également une entrée de table de fonctions. Une fonction frame nécessite un prologue et un épilogue. Une fonction frame peut allouer dynamiquement de l’espace de pile et utiliser un pointeur d’image. Une fonction frame dispose des fonctionnalités complètes de cette norme appelante à sa disposition.
Si une fonction frame n’appelle pas une autre fonction, il n’est pas nécessaire d’aligner la pile (référencée dans l’allocation de la pile de sections).
Une fonction feuille est une fonction qui ne nécessite pas d’entrée de table de fonctions. Il ne peut pas apporter de modifications aux registres nonvolatiles, y compris le RSP, ce qui signifie qu’il ne peut pas appeler de fonctions ni allouer d’espace de pile. Il est autorisé à laisser la pile non alignée pendant son exécution.
alignement malloc
malloc est garanti pour retourner la mémoire qui est correctement alignée pour stocker tout objet ayant un alignement fondamental et qui peut s’adapter à la quantité de mémoire allouée. Un alignement fondamental est un alignement inférieur ou égal à l’alignement le plus important pris en charge par l’implémentation sans spécification d’alignement. (En Visual C++, il s’agit de l’alignement requis pour un double
ou 8 octets. Dans le code qui cible les plateformes 64 bits, il s’agit de 16 octets.) Par exemple, une allocation de quatre octets est alignée sur une limite qui prend en charge n’importe quel objet de quatre octets ou plus petit.
Visual C++ autorise les types qui ont un alignement étendu, également appelé types sur-alignés . Par exemple, les types SSE __m128 et __m256
, et les types déclarés à l’aide de l’emplacement n
__declspec(align( n ))
supérieur à 8, ont un alignement étendu. L’alignement de la mémoire sur une limite adaptée à un objet nécessitant un alignement étendu n’est pas garanti par malloc
. Pour allouer de la mémoire pour les types sur-alignés, utilisez _aligned_malloc et les fonctions associées.
alloca
_alloca doit être aligné sur 16 octets et doit également utiliser un pointeur d’image.
La pile allouée doit inclure de l’espace après avoir été affectée pour les paramètres des fonctions appelées ultérieurement, comme indiqué dans l’allocation de pile.