En informatique , une convention d'appel est un schéma de bas niveau ( implémentation ) définissant comment les sous-programmes ou fonctions reçoivent des paramètres de leur app...
Worldlex WikiFrancaisLecture gratuite
En informatique , une convention d'appel est un schéma de bas niveau ( implémentation ) définissant comment les sous-programmes ou fonctions reçoivent des paramètres de leur appelant et comment ils renvoient un résultat. Lorsqu'un programme appelle une fonction, des choix de conception déterminent où et comment les paramètres sont passés à cette fonction, et où et comment les résultats sont renvoyés. Ces transferts s'effectuent généralement via certains registres ou au sein d'un cadre de pile sur la pile d'appels . Des choix de conception définissent également comment les tâches de préparation d'un appel de fonction et de restauration de l'environnement après l'exécution de la fonction sont réparties entre l'appelant et l'appelé. Une convention d'appel spécifie la manière dont chaque fonction doit être appelée. La convention d'appel correcte doit être utilisée pour chaque appel de fonction afin de garantir l'exécution correcte et fiable de l'ensemble du programme utilisant ces fonctions.
Introduction
Les conventions d'appel sont généralement considérées comme faisant partie de l' interface binaire de l'application (ABI). Elles peuvent être considérées comme un contrat entre l'appelant et la fonction appelée.
Concepts connexes
Les noms et significations des paramètres et des valeurs de retour sont définis dans l' interface de programmation (API, par opposition à l'ABI), un concept distinct mais lié à l'ABI et aux conventions d'appel. Les noms des membres des structures et objets passés en paramètre font également partie de l'API, et non de l'ABI. Les API incluent parfois des mots-clés pour spécifier les conventions d'appel des fonctions.
Les conventions d'appel ne contiennent généralement pas d'informations sur la gestion de la durée de vie des structures et objets alloués dynamiquement. D'autres documents complémentaires peuvent indiquer à qui incombe la responsabilité de libérer la mémoire allouée.
Les conventions d'appel ne précisent généralement pas la disposition des éléments au sein des structures et des objets, comme l'ordre des octets ou le compactage des structures.
Pour certains langages, la convention d'appel inclut des détails sur la gestion des erreurs ou des exceptions (par exemple Go , Java ), et pour d'autres, elle ne le fait pas (par exemple C++ ).
Les conventions d'appel peuvent être liées à la stratégie d'évaluation d'un langage de programmation particulier , mais elles ne sont généralement pas considérées comme en faisant partie (ou vice versa), car la stratégie d'évaluation est généralement définie à un niveau d'abstraction plus élevé et considérée comme faisant partie du langage plutôt que comme un détail d'implémentation de bas niveau du compilateur d'un langage particulier .
Différentes conventions d'appel
Les conventions d'appel peuvent différer selon :
Emplacement des paramètres. Les options incluent les registres , la pile d'appels , une combinaison des deux, ou d'autres structures de mémoire.
L'ordre dans lequel les paramètres sont transmis. Les options incluent l'ordre de gauche à droite, de droite à gauche, ou un ordre plus complexe.
Gestion des fonctions prenant un nombre variable d'arguments ( fonctions variadiques ). Les options incluent la passation des arguments dans l'ordre (en supposant que le premier paramètre soit placé de manière évidente) ou la passation des arguments variables dans un tableau.
La manière dont les valeurs de retour sont transmises de l'appelé à l'appelant peut être : sur la pile, dans un registre ou via une référence à une variable allouée sur le tas.
La manière dont les valeurs longues ou complexes sont gérées, par exemple en les répartissant sur plusieurs registres, au sein du cadre de pile, ou en faisant référence à la mémoire.
Quels registres sont garantis de conserver la même valeur au retour de l'appelé qu'au moment de l'appel ? Ces registres sont dits sauvegardés ou préservés , et ne sont donc pas volatils .
Comment les tâches de préparation et de nettoyage après un appel de fonction sont réparties entre l'appelant et l'appelé ? Plus précisément, comment la pile d'exécution est-elle restaurée pour permettre à l'appelant de poursuivre son exécution une fois que l'appelé a terminé ?
Si et comment les métadonnées décrivant les arguments sont transmises
L'emplacement où est stockée la valeur précédente du pointeur de cadre , utilisée pour restaurer le cadre de pile à la fin de la sous-routine. Ce pointeur peut être stocké dans la pile d'appels ou dans un registre spécifique. Il arrive que les pointeurs de cadre ne soient pas utilisés du tout.
Où sont placés les liens de portée statique pour l'accès aux données non locales de la routine (généralement à une ou plusieurs positions dans le cadre de pile, mais parfois dans un registre général, ou, pour certaines architectures, dans des registres à usage spécifique)
Pour les langages orientés objet, la manière dont l'objet de la fonction est référencé
Conventions d'appel au sein d'une même plateforme
Il arrive que plusieurs conventions d'appel coexistent sur une même plateforme ; une plateforme et une implémentation de langage données peuvent proposer un choix de conventions d'appel. Ceci s'explique notamment par des raisons de performance, l'adaptation aux conventions d'autres langages populaires et les restrictions ou conventions imposées par les différentes plateformes informatiques .
De nombreuses architectures n'ont qu'une seule convention d'appel largement utilisée, souvent proposée par l'architecte. Pour les architectures RISC , notamment SPARC, MIPS et RISC-V , les noms de registres basés sur cette convention sont fréquemment employés. Par exemple, les registres MIPS de 0 La convention d'appel du langage d'un programme peut différer de celle de la plateforme sous-jacente, du système d'exploitation ou d'une bibliothèque utilisée. Par exemple, sous Windows 32 bits , les appels système utilisent la convention `stdcall` , tandis que de nombreux programmes C exécutés sous ce système utilisent la convention `cdecl` . Pour gérer ces différences, les compilateurs autorisent souvent des mots-clés spécifiant la convention d'appel d'une fonction. Les déclarations de fonctions incluent alors des mots-clés supplémentaires spécifiques à la plateforme, indiquant la convention à utiliser. Correctement gérés, ces mots-clés permettent au compilateur de générer le code appelant les fonctions de manière appropriée.
Certains langages permettent de spécifier explicitement la convention d'appel d'une fonction avec cette fonction ; d'autres langages auront une convention d'appel, mais celle-ci sera cachée aux utilisateurs du langage et ne sera donc généralement pas prise en compte par le programmeur.
Architectures
x86 (32 bits)
push EAX ; passer un résultat de registre push dword [ EBP + 20 ] ; passer une variable mémoire (syntaxe FASM/TASM) push 3 ; passer une constante call calc ; le résultat retourné est maintenant dans EAX
Structure typique de l'appelé : (certaines ou toutes les instructions ci-dessous (sauf ret) peuvent être optimisées dans les procédures simples). Certaines conventions conservent l'espace des paramètres alloué, en utilisant simplement calc: push EBP ; sauvegarde de l'ancien pointeur de cadre mov EBP , ESP ; obtient le nouveau pointeur de cadre sub ESP , localsize ; réserve de l'espace de pile pour les variables locales . . ; effectue les calculs, laisse le résultat dans EAX . mov ESP , EBP ; libère de l'espace pour les variables locales pop EBP ; restaure l'ancien pointeur de cadre ret paramsize ; libère l'espace des paramètres et retourne.
r15 : Compteur de programme (conformément à la spécification du jeu d'instructions).
r14 : Registre de liaison . L’instruction BL, utilisée dans un appel de sous-programme, stocke l’adresse de retour dans ce registre.
r13 : Pointeur de pile . Les instructions Push/Pop en mode de fonctionnement « Thumb » utilisent uniquement ce registre.
r12 : Registre de travail d'appel intra-procédure.
r4 à r11 : Variables locales.
r0 à r3 : Valeurs des arguments passés à une sous-routine et résultats renvoyés par une sous-routine.
Si le type de valeur renvoyée est trop grand pour tenir dans r0 à r3, ou si sa taille ne peut pas être déterminée statiquement au moment de la compilation, alors l'appelant doit allouer de l'espace pour cette valeur au moment de l'exécution et passer un pointeur vers cet espace dans r0.
Les sous-programmes doivent préserver le contenu des registres r4 à r11 ainsi que le pointeur de pile (par exemple, en les sauvegardant sur la pile dans le prologue de la fonction , puis en les utilisant comme espace de travail, et enfin en les restaurant depuis la pile dans l' épilogue ). Plus précisément, les sous-programmes appelant d'autres sous-programmes doivent sauvegarder l'adresse de retour dans le registre de liaison r14 sur la pile avant d'appeler ces autres sous-programmes. Cependant, ces sous-programmes n'ont pas besoin de renvoyer cette valeur dans r14 ; il leur suffit de la charger dans r15, le compteur de programme, pour se terminer.
La convention d'appel ARM impose l'utilisation d'une pile descendante complète. De plus, le pointeur de pile doit toujours être aligné sur 4 octets, et sur 8 octets lors d'un appel de fonction avec une interface publique.
Cette convention d'appel entraîne le comportement d'une sous-routine ARM « typique » :
Dans le prologue, empilez les valeurs de r4 à r11 et empilez l'adresse de retour contenue dans r14 (ceci peut être réalisé avec une seule instruction STM) ;
Copiez tous les arguments passés (dans r0 à r3) dans les registres temporaires locaux (r4 à r11) ;
Allouer les autres variables locales aux registres temporaires locaux restants (r4 à r11) ;
Effectuez les calculs et appelez d'autres sous-routines si nécessaire en utilisant BL, en supposant que r0 à r3, r12 et r14 ne seront pas préservés ;
Placez le résultat dans r0 ;
Dans l'épilogue, extrayez les valeurs de r4 à r11 de la pile, et stockez l'adresse de retour dans le compteur de programme r15. Ceci peut être réalisé avec une seule instruction LDM.
ARM (A64)
La convention d'appel ARM 64 bits ( AArch64 ) alloue les 31 registres à usage général comme suit :
x31 (SP) : Pointeur de pile ou registre zéro , selon le contexte.
x30 (LR) : Registre de liaison de procédure, utilisé pour revenir des sous-routines.
x18 (PR) : Registre de plateforme. Utilisé à des fins spécifiques au système d’exploitation ou comme registre supplémentaire sauvegardé par l’appelant.
x16 (IP0) et x17 (IP1) : Registres temporaires d'appel intra-procédure.
x9 à x15 : Variables locales, appelant enregistré.
x8 (XR) : Adresse de valeur de retour indirecte.
x0 à x7 : Valeurs des arguments passés à une sous-routine et résultats renvoyés par celle-ci.
Tous les registres commençant par x ont un registre 32 bits correspondant préfixé par w . Ainsi, un registre 32 bits x0 est appelé w0.
De même, les 32 registres à virgule flottante sont alloués comme suit :
v0 à v7 : Valeurs des arguments passés à une sous-routine et résultats renvoyés par celle-ci.
v8 à v15 : l’appelé est sauvegardé, mais seuls les 64 bits de poids faible doivent être conservés.
v16 à v31 : Variables locales, appelant enregistré.
RISC-V ISA
RISC-V possède une convention d'appel définie avec deux variantes, avec ou sans matériel à virgule flottante. Il passe les arguments dans les registres chaque fois que cela est possible.
POWER, PowerPC et Power ISA
Les architectures POWER , PowerPC et Power ISA disposent d'un grand nombre de registres, permettant à la plupart des fonctions de passer tous leurs arguments par registre lors d'appels à un seul niveau . Les arguments supplémentaires sont passés sur la pile, et l'espace nécessaire pour les arguments stockés dans les registres est systématiquement alloué sur la pile. Ceci est particulièrement utile pour la fonction appelée lors d'appels à plusieurs niveaux (récursifs ou non) où les registres doivent être sauvegardés. Cette approche est également pratique pour les fonctions variadiques , telles que Les instructions de branchement et de liaison stockent l'adresse de retour dans un registre de liaison spécial , distinct des registres généraux. Une routine retourne à son appelant avec une instruction de branchement utilisant le registre de liaison comme adresse de destination. Les routines feuilles n'ont pas besoin de sauvegarder ni de restaurer le registre de liaison. Les routines non feuilles doivent sauvegarder l'adresse de retour avant d'appeler une autre routine et la restaurer avant de retourner leur appelant. La sauvegarde s'effectue en déplaçant le registre de liaison vers un registre général à l'aide de l'instruction « Déplacer depuis un registre spécial », puis, si nécessaire, en l'empilant. La restauration s'effectue en chargeant la valeur sauvegardée du registre de liaison dans un registre général, puis en utilisant l'instruction « Déplacer vers un registre spécial » pour déplacer ce registre vers le registre de liaison.
MIPS
V , que la plupart des systèmes modernes de type Unix suivent, transmet les six premiers arguments dans les registres "in" %i0 à %i5, réservant %i6 pour le pointeur de cadre et %i7 pour l'adresse de retour.
LA 1,ARGS Charger l'adresse de la liste des arguments L 15,=V(SUB) Charger l'adresse de la sous-routine 1 BALR 14,15 Branchement vers la routine appelée 2 ... ARGS DC A(PREMIER) Adresse du 1er argument DC A(DEUXIÈME) ... DC A(TROISIÈME)+X'80000000' Dernier argument 3
Programme appelé :
SUB EQU * Il s'agit du point d'entrée du sous-programme 4
Séquence d'entrée standard :
UTILISATION *,15 5 STM 14,12,12(13) Sauvegarder les registres 6 ST 13, SAVE+4 Enregistrer l'adresse de la zone de sauvegarde de l'appelant LA 12,SAVE Chaîne zones de stockage ST 12,8(13) LR 13,12 ...
Séquence de retour standard :
L 13, ÉCONOMISEZ +4 7 LM 14,12,12(13) L 15,RETVAL 8 BR 14 Retour à l'appelant SAUVEGARDER DS 18F Zone de sauvegarde 9
Remarques :
Utilisez L' ( registre 14 ) et effectue un branchement vers l'adresse du deuxième argument, stockée dans le registre 15. BASR est privilégié sur les modèles compatibles. BASSM peut être utilisé si la commutation entre les modes 24 et 31 bits est nécessaire.
L'appelant transmet l'adresse d'une liste d'adresses d'arguments dans le registre 1. Le bit de poids fort de la dernière adresse est activé pour indiquer la fin de la liste. Ceci limite les programmes utilisant cette convention à un adressage sur 31 bits .
Pour les sous-programmes externes, incluez-les L'adresse de la routine appelée se trouve dans le registre 15. Normalement, celle-ci est chargée dans un autre registre, informant ainsi L' instruction sauvegarde les registres 14, 15 et 0 à 12 dans une zone de sauvegarde La séquence de retour restaure les registres de l'appelant.
Le registre 15 est généralement utilisé pour transmettre un code de retour. Le code présenté est incorrect, mais il illustre le principe.
Déclarer une saveareavariable statique dans la routine appelée la rend non réentrante et non récursive ; un programme réentrant utilise une variable dynamique savearea, acquise soit auprès du système d'exploitation et libérée au retour, soit dans un espace de stockage transmis par le programme appelant.
Les registres 2 et 3 sont utilisés pour le passage des paramètres et les valeurs de retour
Les registres 4 et 5 sont également utilisés pour le passage des paramètres.
Le registre 6 est utilisé pour le passage de paramètres et doit être sauvegardé et restauré par l'appelé.
Les registres 7 à 13 sont réservés à l'utilisateur appelé et doivent être sauvegardés et restaurés par celui-ci.
Le registre 14 est utilisé pour l'adresse de retour
Le registre 15 est utilisé comme pointeur de pile.
Les registres à virgule flottante 0 et 2 sont utilisés pour le passage des paramètres et les valeurs de retour.
Les registres à virgule flottante 4 et 6 sont destinés à être utilisés par l'appelé et doivent être sauvegardés et restaurés par celui-ci.
Dans z/Architecture, les registres à virgule flottante 1, 3, 5 et 7 à 15 sont réservés à l'appelé.
Le registre d'accès 0 est réservé à l'usage du système.
Les registres d'accès 1 à 15 sont réservés à l'appelé.
Des arguments supplémentaires sont transmis sur la pile.
SuperH
L' IBM 1130 était une petite machine 16 bits adressable par mot. Elle ne possédait que six registres, plus des indicateurs d'état, et aucune pile. Ces registres sont le registre d'adresse d'instruction (IAR) , l'accumulateur (ACC) , l'extension d'accumulateur (EXT) et trois registres d'index X1 à X3. Le programme appelant est responsable de la sauvegarde de ACC, EXT, X1 et X2. Deux pseudo-opérations permettent d'appeler des sous-programmes : vecteur de transfert . Ces deux pseudo-opérations correspondent à une instruction machine IAR de branchement et de stockageLes arguments suivent l'adresse — — routine appelée doit connaître le nombre d'arguments attendus afin de pouvoir les ignorer au retour. Les arguments peuvent également être passés par registres. Les routines de fonction renvoyaient le résultat dans l'ACC pour les arguments réels, ou dans une adresse mémoire appelée pseudo-accumulateur de nombres réels (FAC). Les arguments et l'adresse de retour étaient adressés à l'aide d'un décalage par rapport à la valeur IAR stockée au premier emplacement de la sous-routine.
Les sous-programmes des IBM 1130, CDC 6600 et PDP-8 (ces trois ordinateurs ont été introduits en 1965) stockent l'adresse de retour dans le premier emplacement d'un sous-programme.
Conventions d'appel en dehors des architectures de machines
Code multithread
PL/I
La convention d'appel par défaut pour les programmes écrits en PL/I passe tous les arguments par référence , bien que d'autres conventions puissent être spécifiées. Le traitement des arguments varie selon les compilateurs et les plateformes, mais généralement, leurs adresses sont passées via une liste d'arguments en mémoire. Une adresse finale, cachée, peut être fournie pour pointer vers une zone mémoire destinée à contenir la valeur de retour. Du fait de la grande variété de types de données pris en charge par PL/I, un descripteur de données peut également être fourni pour définir, par exemple, la longueur des chaînes de caractères ou de bits, les dimensions et les limites des tableaux ( vecteurs de données ), ou encore la structure et le contenu d'une structure de données . Des arguments fictifs sont créés pour les arguments constants ou dont le type ne correspond pas à celui attendu par la procédure appelée.