En informatique, une convention d'appel est un ensemble de règles qui décrit comment une fonction reçoit des paramètres et renvoie un résultat. Cela inclut des choix techniques sur où et comment les informations sont envoyées à la fonction appelée, et où et comment le résultat est renvoyé. En général, ces transferts se font soit par des registres, soit en utilisant une "pile" spéciale qui stocke temporairement des informations.

Il y a aussi des règles pour déterminer qui, entre l'appelant (celui qui appelle la fonction) et l'appelé (la fonction elle-même), est responsable de préparer et nettoyer après l'appel. Respecter la convention d'appel est essentiel pour que le programme fonctionne correctement et sans erreurs.

Introduction Les conventions d’appel font généralement partie de l’interface binaire d’une application (ABI). Elles servent de contrat entre celui qui appelle la fonction et la fonction elle-même.

Concepts connexes Les noms et significations des paramètres et des valeurs de retour sont définis dans l'interface de programmation d'application (API), qui est liée mais distincte de l'ABI et de la convention d'appel. Les noms des éléments à l'intérieur des structures et des objets transmis font aussi partie de l'API, pas de l'ABI. Parfois, les API incluent des mots-clés pour indiquer la convention d'appel des fonctions.

Les conventions d’appel n’incluent généralement pas d’informations sur la gestion de la durée de vie des structures et objets alloués dynamiquement. D'autres documentations complémentaires peuvent indiquer à qui incombe la responsabilité de libérer la mémoire allouée.

Il est peu probable que les conventions d'appel spécifient la disposition des éléments dans les structures et les objets, comme l'ordre des octets ou le regroupement 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, ce n'est pas le cas (par exemple C++ ).

Pour les appels de procédure à distance, il existe un concept analogue appelé Marshalling.

Les conventions d'appel peuvent être influencées par la stratégie d'évaluation d'un langage de programmation, mais elles ne sont généralement pas considérées comme faisant partie du langage lui-même. La stratégie d'évaluation appartient à un niveau d'abstraction plus élevé, défini comme une caractéristique du langage, tandis que les conventions d'appel relèvent des détails d'implémentation à bas niveau du compilateur.

Différentes conventions d’appel Les conventions d’appel peuvent différer dans :

Où sont placés les paramètres. Les options incluent des registres, sur la pile d'appels, un mélange des deux ou dans d'autres structures de mémoire. L'ordre dans lequel les paramètres sont passés. Les options incluent l'ordre de gauche à droite, ou de droite à gauche, ou quelque chose de plus complexe. Comment les fonctions qui prennent un nombre variable d'arguments ( fonctions variadiques ) sont gérées. Les options incluent simplement les éléments passés dans l'ordre (en supposant que le premier paramètre soit dans une position évidente) ou les parties variables d'un tableau. Comment les valeurs de retour sont transmises de l'appelé à l'appelant. Les options incluent sur la pile, dans un registre ou une référence à quelque chose alloué sur le tas. La longueur ou la complexité des valeurs traitées, peut-être en les répartissant sur plusieurs registres, dans le cadre de la pile ou en référence à la mémoire. Quels registres sont garantis d'avoir la même valeur lorsque l'appelé revient que lorsqu'il a été appelé. Ces registres sont dits sauvegardés ou préservés, ils ne sont donc pas volatils. Comment la tâche de configuration et de nettoyage après un appel de fonction est divisée entre l'appelant et l'appelé. En particulier, comment la trame de pile est restaurée afin que l'appelant puisse continuer une fois que l'appelé a terminé. Si et comment les métadonnées décrivant les arguments sont transmises Où la valeur précédente du pointeur de trame est stockée, qui est utilisée pour restaurer la trame de pile lorsque la sous-routine se termine. Les options sont incluses dans la pile d'appels ou dans un registre spécifique. Parfois, les pointeurs de trame ne sont 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 la pile, mais parfois dans un registre général ou, pour certaines architectures, dans des registres à usage spécial) Pour les langages orientés objet, comment l'objet de la fonction est référencé

Conventions d'appel au sein d'une même plateforme Sur une même plateforme, il peut exister plusieurs conventions d'appel, et une combinaison spécifique de plateforme et de langage peut proposer différents choix. Cela permet d’optimiser les performances, de s’adapter aux conventions d'autres langages populaires ou de respecter les exigences imposées par diverses plateformes informatiques.

De nombreuses architectures utilisent une seule convention d'appel, souvent recommandée par l'architecte du système. Pour les architectures RISC comme SPARC, MIPS et RISC-V, les registres sont nommés en fonction de cette convention. Par exemple, sur MIPS, les registres $4 à $7 sont nommés $a0 à $a3 pour indiquer qu'ils servent à passer des paramètres selon la convention d'appel standard. (Les processeurs RISC disposent de nombreux registres à usage général identiques, donc il n'y a généralement pas de raison matérielle de les nommer autrement que par des numéros.)

La convention d'appel d'un langage peut être différente de celle de la plateforme, du système d'exploitation ou des bibliothèques auxquelles il est lié. Par exemple, sous Windows 32 bits, les appels système utilisent la convention d'appel stdcall, tandis que de nombreux programmes C utilisent la convention cdecl. Pour gérer ces différences, les compilateurs permettent souvent d'ajouter des mots-clés aux déclarations de fonction pour spécifier la convention d'appel à utiliser. Cela permet au compilateur de générer le code nécessaire pour appeler les fonctions correctement.

Certains langages permettent de définir explicitement la convention d'appel d'une fonction, tandis que d'autres imposent une convention sans la rendre visible aux utilisateurs, de sorte que le programmeur n’a généralement pas à s'en soucier.

Architectures

x86 (32 bits) push EAX ; passer le contenu du registre push dword [EBP+20] ; passer une variable mémoire (syntaxe FASM/TASM) push 3 ; pass une constante call calc ; La valeur retournée est dans EAXL'architecture x86 en 32 bits utilise de nombreuses conventions d'appel. Étant donné le faible nombre de registres disponibles et la priorité historique donnée à la simplicité et à la compacité du code, de nombreuses conventions d'appel x86 passent les arguments via la pile, et renvoient la valeur de retour (ou un pointeur vers celle-ci) dans un registre. Certaines conventions passent les premiers paramètres dans des registres, ce qui peut améliorer les performances, notamment pour les routines simples et courtes appelées fréquemment (celles qui n'appellent pas d'autres fonctions).

Exemple d'appel :calc: push EBP ; Sauvegarder l'ancien frame pointer mov EBP,ESP ; Avoir un nouveau pointeur de frame sub ESP,localsize ; Reserver de l'espace pour les variables locales . . ; Faire des calculs, laisser le resultat dans EAX . mov ESP,EBP ; Liberer l'espace utilisé par les variables locales pop EBP ; Restaurer l'ancien frame pointer ret paramsize ; Liberer l'espace utilisé par les parametres et returnStructure d'appel typique : (certaines ou toutes les instructions ci-dessous, sauf `ret`, peuvent être optimisées dans des procédures simples). Certaines conventions laissent l'espace pour les paramètres alloué, en utilisant `ret` simple au lieu de `ret imm16`. Dans ce cas, l'appelant pourrait utiliser `add esp, 12` dans cet exemple, ou ajuster autrement ESP.

x86-64 * 1130 subroutine example ENT SUB Declare "SUB" an external entry point SUB DC 0 Reserved word at entry point, conventionally coded "DC *-*" * Subroutine code begins here * If there were arguments the addresses can be loaded indirectly from the return address LDX I 1 SUB Load X1 with the address of the first argument (for example) ... * Return sequence LD RES Load integer result into ACC * If no arguments were provided, indirect branch to the stored return address B I SUB If no arguments were provided END SUBLa version 64 bits de l'architecture x86, appelée x86-64, AMD64 ou Intel 64, utilise deux séquences d'appel courantes. La première, définie par Microsoft, est utilisée sous Windows ; la seconde, spécifiée dans l'ABI AMD64 System V, est utilisée par les systèmes de type Unix et, avec quelques modifications, par OpenVMS. Étant donné que le x86-64 dispose de plus de registres à usage général que le x86 en 32 bits, les deux conventions transmettent certains arguments directement dans des registres.

BRAS (A32) La convention d'appel ARM 32 bits standard alloue les 16 registres à usage général comme suit :

r15 : Compteur de programme (conformément à la spécification du jeu d'instructions). r14 : Registre de liens. 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 d’argument transmises à une sous-routine et résultats renvoyés par une sous-routine.

Si la valeur renvoyée est trop grande pour tenir dans les registres r0 à r3, ou si sa taille ne peut pas être déterminée statiquement lors de la compilation, l'appelant doit allouer de l'espace pour cette valeur pendant l'exécution et passer un pointeur vers cet espace dans r0.

Les sous-routines doivent conserver le contenu des registres r4 à r11 ainsi que le pointeur de pile. Cela peut être fait en les enregistrant dans la pile au début de la fonction (prologue), puis en les utilisant comme espace de travail, et enfin en les restaurant à partir de la pile à la fin de la fonction (épilogue). De plus, les sous-routines qui appellent d'autres sous-routines doivent sauvegarder l'adresse de retour dans le registre de liaison r14, en la plaçant dans la pile avant l'appel. Toutefois, ces sous-routines n'ont pas besoin de renvoyer cette valeur à r14 ; elles doivent simplement la charger dans r15, le compteur de programme, pour revenir.

La convention d'appel ARM exige l'utilisation d'une pile entièrement descendante. 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 amène une sous-routine ARM « typique » à :

Dans le prologue, poussez r4 vers r11 vers la pile, et poussez l'adresse de retour dans r14 vers la pile (cela peut être fait avec une seule instruction STM) ; Copiez tous les arguments passés (de r0 à r3) dans les registres de travail locaux (r4 à r11) ; Allouer d’autres variables locales aux registres de travail locaux restants (r4 à r11) ; Effectuez des 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 ; Mettre le résultat dans r0 ; Dans l'épilogue, tirez r4 à r11 de la pile et tirez l'adresse de retour vers le compteur de programme r15. Cela peut être fait avec une seule instruction LDM.

BRAS (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 lien de procédure, utilisé pour revenir des sous-routines. x29 (FP) : Pointeur de cadre. x19 à x28 : appelé enregistré.