Assembleur 80x86 | CALL |
---|---|
INTEL 8088+, x86-64 | CALL |
Syntaxe
CALL adresse |
Paramètres
Nom | Description |
---|---|
adresse | Ce paramètre permet d'indiquer l'adresse où est situé le sous-programme. |
Description
Cette instruction force le microprocesseur à exécuter les instructions du sous-programme indiqué par l'adresse d'appel avant de continuer. Dès que la routine est terminé, l'exécution reprendra son cours à l'instruction suivant le CALL. Ainsi, par conséquent, l'instruction CALL enregistre les informations de liaison de procédure sur la pile et les branches à la procédure appelée spécifiée à l'aide de l'adresse spécifié. L'opérande de l'adresse peut être une valeur immédiate, un registre à usage général ou un emplacement de mémoire. Cette instruction peut être utilisée pour exécuter quatre types d'appels :
- Appel court (Near Call) :Appel à une procédure du segment de code actuel (segment actuellement désigné par le registre CS), parfois appelé appel intra-segment.
- Appel long (Far Call) : Appel à une procédure située dans un segment différent du segment de code actuel, parfois appelé appel inter-segment.
- Appel de niveau inter-privilège (Inter-privilege-level far call) : Appel long d'une procédure d'un segment ayant un niveau de privilège différent de celui du programme ou de la procédure en cours d'exécution.
- Commutation de tâche (Task switch) : Appel à une procédure située dans une tâche différente.
Remarques
- Les appels Inter-privilege-level far call (appel de niveau inter-privilège) et Task switch (commutation de tâche) ne peuvent être exécutés qu'en mode protégé.
- Appel court Near Call : Lors de l'exécution d'un appel court, le microprocesseur transmet la valeur du registre EIP (contenant le déplacement de l'instruction suivant l'instruction CALL) sur la pile (pour une utilisation ultérieure en tant que pointeur d'instruction de retour). Le microprocesseur se connecte ensuite à l'adresse du segment de code actuel spécifié par l'opérande cible. L'opérande cible spécifie soit un déplacement absolu dans le segment de code (un déplacement par rapport à la base du segment de code), soit un déplacement relatif (un déplacement signé par rapport à la valeur actuelle du pointeur d'instruction dans le registre EIP; cette valeur pointe vers le instruction suivant l'instruction CALL). Le registre CS n'est pas modifié pour les appels courts. Pour un appel court absolu, un déplacement absolu est spécifié indirectement dans un registre à usage général ou un emplacement de mémoire (r/m16, r/m32 ou r/m64). L'attribut de taille d'opérande détermine la taille de l'opérande cible (16, 32 ou 64 bits). En mode 64 bits, la taille de l'opérande pour l'appel court (et toutes les branches courtes) est forcée à 64 bits. Les déplacements absolus sont chargés directement dans le registre EIP (RIP). Si l'attribut de taille d'opérande est 16, les 2 octets supérieurs du registre EIP sont effacés, ce qui donne une taille maximale du pointeur d'instruction de 16 bits. Lors de l'accès indirect à un déplacement absolu en utilisant le pointeur de pile [ESP] comme registre de base, la valeur de base utilisée est la valeur de l'ESP avant l'exécution de l'instruction. Un déplacement relatif (rel16 ou rel32) est généralement spécifié en tant qu'étiquette dans le code d'assemblage. Mais au niveau du code machine, il est codé comme une valeur immédiate signée, 16 ou 32 bits. Cette valeur est ajoutée à la valeur dans le registre EIP (RIP). En mode 64 bits, le déplacement relatif est toujours une valeur immédiate de 32 bits étant un signe étendu à 64 bits avant d'être ajoutée à la valeur du registre RIP pour le calcul de la cible. Comme pour les déplacements absolus, l'attribut de taille d'opérande détermine la taille de l'opérande cible (16, 32 ou 64 bits). En mode 64 bits, l'opérande cible sera toujours 64 bits car la taille de l'opérande est forcée à 64 bits pour les branches courtes.
- Appels long en mode d'adressage réel ou virtuelle-8086 : Lors de l'exécution d'un appel long en mode d'adresse réelle ou virtuelle-8086, le microprocesseur transmet la valeur actuelle des registres CS et EIP de la pile afin qu'elle soit utilisée comme pointeur d'instruction de retour. Le microprocesseur effectue ensuite un «branchement longue» vers le segment de code et le déplacement spécifié avec l'opérande cible pour la procédure appelée. L'opérande cible spécifie une adresse longue absolue soit directement avec un pointeur (ptr16:16 ou ptr16:32), soit indirectement avec un emplacement mémoire (m16:16 ou m16:32). Avec la méthode du pointeur, le segment et le décalage de la procédure appelée sont codés dans l'instruction à l'aide d'une adresse longue de 4 octets (taille d'opérande de 16 bits) ou de 6 octets (taille d'opérande de 32 bits). Avec la méthode indirecte, l'opérande cible spécifie un emplacement mémoire contenant une adresse longue de 4 octets (taille d'opérande de 16 bits) ou de 6 octets (taille d'opérande de 32 bits). L'attribut de taille d'opérande détermine la taille du déplacement (16 ou 32 bits) dans l'adresse longue. L'adresse longue est chargée directement dans les registres CS et EIP. Si l'attribut de la taille d'opérande est 16, les 2 octets supérieurs du registre EIP sont effacés.
- Appels longs en mode protégé : Lorsque le microprocesseur fonctionne en mode protégé, l'instruction CALL peut être utilisée pour effectuer les types d'appels éloignés suivants : Appel long au même niveau de privilège, appel long à un niveau de privilège différent (appel de niveau inter-privilège), commutation de tâche (appel long vers une autre tâche). En mode protégé, le microprocesseur utilise toujours la partie du sélecteur de segment de l'adresse long pour accéder au descripteur correspondant dans le GDT ou le LDT. Le type de descripteur (segment de code, porte d'appel, porte de tâche ou TSS) et les droits d'accès déterminent le type d'opération à effectuer. Si le descripteur sélectionné concerne un segment de code, un appel éloigné à un segment de code au même niveau de privilège est effectué (si le segment de code sélectionné se trouve à un niveau de privilège différent et que le segment de code est non conforme, une exception de protection générale est générée). Un appel long au même niveau de privilège en mode protégé est très similaire à celui effectué en adresse réel ou mode virtuel-8086. L'opérande cible spécifie une adresse extrême absolue soit directement avec un pointeur (ptr16:16 ou ptr16:32), soit indirectement avec un emplacement mémoire (m16:16 ou m16:32). L'attribut de la taille d'opérande détermine la taille du déplacement (16 ou 32 bits) dans l'adresse long. Le nouveau sélecteur de segment de code et son descripteur sont chargés dans le registre CS; le déplacement de l'instruction est chargé dans le registre EIP. Une porte d'appel peut également être utilisée pour effectuer un appel long vers un segment de code au même niveau de privilège. L'utilisation de ce mécanisme fournit un niveau supplémentaire d'indirection et constitue la méthode recommandée pour passer des appels entre des segments de code 16 bits et 32 bits. Lors de l'exécution d'un appel long de niveau inter-privilège, le segment de code de la procédure appelée doit être accessible via une porte d'appel. Le sélecteur de segment spécifié par l'opérande cible identifie la porte d'appel. L'opérande cible peut spécifier le sélecteur de segment de la porte d'appel directement avec un pointeur (ptr16:16 ou ptr16:32) ou indirectement avec un emplacement mémoire (m16:16 ou m16:32). Le microprocesseur obtient le sélecteur de segment pour le nouveau segment de code et le nouveau pointeur d'instruction (déplacement ou offset) à partir du descripteur de porte d'appel (le déplacement par rapport à l'opérande cible est ignoré lorsqu'une porte d'appel est utilisée). Lors d'appels entre niveaux de privilège, le microprocesseur bascule vers la pile pour le niveau de privilège de la procédure appelée. Le sélecteur de segment pour le nouveau segment de pile est spécifié dans le TSS pour la tâche en cours d'exécution. La branche vers le nouveau segment de code se produit après le commutateur de pile (Notez que lorsqu'un commutateur d'appels est utilisé pour effectuer un appel long vers un segment au même niveau de privilège, aucun commutateur de pile ne se produit). Sur la nouvelle pile, le microprocesseur pousse le sélecteur de segment et le pointeur de pile pour la pile de la procédure d'appel, une option ensemble de paramètres de la pile de procédures appelantes, ainsi que le sélecteur de segment et le pointeur d'instruction pour le segment de code de la procédure appelante. (Une valeur dans le descripteur de la porte d'appel détermine le nombre de paramètres à copier dans la nouvelle pile.) Enfin, le processeur se connecte à l'adresse de la procédure appelée dans le nouveau segment de code. L'exécution d'un commutateur de tâche avec l'instruction CALL est similaire à l'exécution d'un appel via une porte d'appels. L'opérande cible spécifie le sélecteur de segment de la porte des tâches pour la nouvelle tâche activée par le commutateur (le déplacement dans l'opérande cible est ignoré). La porte des tâches pointe à son tour sur le TSS pour la nouvelle tâche, contenant les sélecteurs de segment pour les segments de code et de pile de la tâche. Notez que le TSS contient également la valeur EIP de la prochaine instruction à exécuter avant la suspension de la tâche appelante. Cette valeur de pointeur d'instruction est chargée dans le registre EIP pour redémarrer la tâche appelante. L'instruction CALL peut également spécifier directement le sélecteur de segment du TSS, ceci éliminant l'indirection de la porte des tâches. Lorsque vous exécutez le commutateur de tâches avec une instruction CALL, le drapeau de tâche imbriquée (NT) est défini dans le registre EFLAGS et le champ de lien de tâche précédent du nouveau TSS est chargé avec le sélecteur TSS de l'ancienne tâche. Le code devrait suspendre cette tâche imbriquée en exécutant une instruction IRET qui, du fait que le drapeau NT est défini, utilise automatiquement le lien de tâche précédent pour revenir à la tâche appelante. La commutation de tâches avec l'instruction CALL diffère à cet égard de l'instruction JMP. L'instruction JMP ne définit pas le drapeau NT et ne s'attend donc pas à une instruction IRET pour suspendre la tâche.
- Mélanger des appels 16 bits et 32 bits : Lorsque vous effectuez des appels longs entre des segments de code 16 bits et 32 bits, utilisez une porte d'appel. Si l'appel long va d'un segment de code 32 bits à un segment de code 16 bits, l'appel doit être effectué à partir des 64 premiers Ko du segment de code 32 bits. En effet, l'attribut de taille d'opérande de l'instruction est défini sur 16, de sorte que seul un déplacement d'adresse de retour de 16 bits peut être enregistré. En outre, l'appel doit être effectué à l'aide d'une porte d'appel 16 bits afin que les valeurs 16 bits puissent être insérées dans la pile.
- Appels long en mode de compatibilité : Lorsque le microprocesseur fonctionne en mode de compatibilité, l'instruction CALL peut être utilisée pour effectuer les types d'appels éloignés suivants : un appel long au même niveau de privilège, restant en mode de compatibilité; un appel long au même niveau de privilège, passant au mode 64 bits; un appel long à un niveau de privilège différent (appel de niveau inter-privilège), passage au mode 64 bits. Notez qu'une instruction CALL ne peut pas être utilisée pour provoquer un changement de tâche en mode de compatibilité, car les changements de tâche ne sont pas pris en charge en mode IA-32e. En mode de compatibilité, le microprocesseur utilise toujours la partie sélecteur de segment de l'adresse long pour accéder au descripteur correspondant dans le GDT ou le LDT. Le type de descripteur (segment de code, porte d'appel) et les droits d'accès déterminent le type d'opération à effectuer. Si le descripteur sélectionné concerne un segment de code, un appel éloigné à un segment de code au même niveau de privilège est effectué. (Si le segment de code sélectionné a un niveau de privilège différent et que le segment de code est non conforme, une exception de protection générale est générée.) Un appel long au même niveau de privilège en mode de compatibilité est très similaire à celui exécuté en mode protégé. L'opérande cible spécifie une adresse longue absolue soit directement avec un pointeur (ptr16:16 ou ptr16:32), soit indirectement avec un emplacement mémoire (m16:16 ou m16:32). L'attribut de taille opérande détermine la taille du déplacement (16 ou 32 bits) dans l'adresse longue. Le nouveau sélecteur de segment de code et son descripteur sont chargés dans le registre CS et le déplacement par rapport à l'instruction est chargé dans le registre EIP. La différence est que le mode 64 bits peut être entré. Ceci est spécifié par le bit L dans le nouveau descripteur de segment de code. Notez qu'une porte d'appel 64 bits peut également être utilisée pour effectuer un appel long vers un segment de code avec le même niveau de privilège. Toutefois, pour utiliser ce mécanisme, le bit L doit être défini sur le descripteur de segment de code cible, ce qui entraîne l'entrée en mode 64 bits. Lors de l'exécution d'un appel long de niveau inter-privilège, le segment de code de la procédure appelée doit être accessible via une porte d'appel de 64 bits. Le sélecteur de segment spécifié par l'opérande cible identifie la porte d'appel. L'opérande peut spécifier le sélecteur de segment de la porte d'appel soit directement avec un pointeur (ptr16:16 ou ptr16:32), soit indirectement avec un emplacement mémoire (m16:16 ou m16:32). Le microprocesseur obtient le sélecteur de segment pour le nouveau segment de code et le nouveau pointeur d'instruction (déplacement) auprès du descripteur de porte d'appel de 16 octets (le déplacement par rapport à l'opérande cible est ignoré lorsqu'une porte d'appel est utilisée). Lors d'appels entre niveaux de privilège, le microprocesseur bascule vers la pile pour le niveau de privilège de la procédure appelée. Le sélecteur de segment pour le nouveau segment de pile est défini sur NULL. Le nouveau pointeur de pile est spécifié dans le TSS pour la tâche en cours d'exécution. La branche vers le nouveau segment de code se produit après le commutateur de pile. (Notez que lorsqu'une porte d'appel est utilisée pour passer un appel long à un segment au même niveau de privilège, un commutateur de pile implicite survient à la suite de l'entrée en mode 64 bits. Le sélecteur de SS n'a pas changé, mais les accès aux segments de pile utilisent un segment de base de 0x0, la limite est ignorée et la taille de pile par défaut est de 64 bits. La valeur entière de RSP est utilisée pour le déplacement, dont les 32 bits supérieurs sont indéfinis.) Sur la nouvelle pile, le microprocesseur pousse le sélecteur de segment et pointeur de pile pour la pile de la procédure appelante et le sélecteur de segment et pointeur d'instruction pour le segment de code de la procédure appelante. (La copie de paramètre n'est pas prise en charge en mode IA-32e.) Enfin, le processeur indique l'adresse de la procédure appelée dans le nouveau segment de code.
- Ordre d'instructions : Les instructions suivant un appel long peuvent être extraites de la mémoire avant la fin de l'exécution des instructions précédentes, mais elles ne s'exécuteront pas (même de manière spéculative) tant que toutes les instructions antérieures à l'appel long ne seront pas terminées (les dernières instructions pourront être exécutées avant les données entreposées par les instructions précédentes soit devenu globalement visible). Certaines situations peuvent conduire à la prochaine instruction séquentielle après qu'un CALL presque indirect ait été exécuté de manière spéculative. Si le logiciel doit empêcher cela (par exemple, afin d'empêcher un canal côté exécution spéculative), un code d'opération d'instruction INT3 ou LFENCE peut être placé après l'appel CALL presque indirect afin de bloquer l'exécution spéculative.
- Si vous programmez avec des microprocesseurs ARM, il faut plutôt utiliser l'instruction «BL» à la place de «CALL».
Algorithme
Appel long | Appel court |
---|---|
PUSH CS PUSH IP CS:IP ← Destination |
PUSH IP IP ← Destination |
Mnémonique
Instruction | Opcode | Description |
---|---|---|
CALL rel16off | E8h iw | Appel court avec une destination spécifié par une adresse 16 bits |
CALL rel32off | E8h id | Appel court avec une destination spécifié par une adresse 32 bits |
CALL reg/mem16 | FFh /2 | Appel court avec une destination spécifié par un registre/mémoire 16 bits |
CALL reg/mem32 | FFh /2 | Appel court avec une destination spécifié par un registre/mémoire 32 bits. Il n'y a pas de préfixe pour l'encoder en mode 64 bits. |
CALL reg/mem64 | FFh /2 | Appel court avec une destination spécifié par un registre/mémoire 64 bits |
CALL FAR pntr16:16 | 9Ah cd | Appel long direct, avec un destination spécifié par un pointeur long. Invalide en mode 64 bits. |
CALL FAR pntr16:32 | 9Ah cp | Appel long direct, avec un destination spécifié par un pointeur long. Invalide en mode 64 bits. |
CALL FAR mem16:16 | FFh /3 | Appel long indirect, avec un destination spécifié par un pointeur long en mémoire. |
CALL FAR mem16:32 | FFh /3 | Appel long indirect, avec un destination spécifié par un pointeur long en mémoire. |
Exceptions
Message | Mode réel | Virtuel 8086 | Mode protégé | Description |
---|---|---|---|---|
#AC(Vérifie l'alignement) | X | X | Un désalignement de la référence mémoire est effectué quand une vérification d'alignement est activé | |
#GP(Protection général) | X | X | X | Une adresse mémoire dépasse la limite du segment de données ou n'est pas canonique |
X | X | X | L'opérande de destination dépasse la limite du segment de code ou n'est pas canonique. | |
X | Un segment de données nulle est utilisé comme référence mémoire | |||
#GP(Sélecteur) | X | Le sélecteur de segment de code de destination est un sélecteur nulle. | ||
X | Un code, d'un appel de pont, de tâche de pont, ou un descripteur TSS dépasse la limite du descripteur de table. | |||
X | Un sélecteur de segment de bit TI est fixer mais le sélecteur LDT est un sélecteur nulle. | |||
X | Le descripteur de segment spécifié par l'instruction n'est pas un segment de code, une tâche de pont, un appel de pont, ou un TSS disponible en mode legacy, ou un segment de code n'étant en mode 64 bits ou un appel de pont 64 bits dans un mode long. | |||
X | Le RPL de sélecteur de segment de code spécifié est non-conforme à une instruction plus grande que le CPL, ou le DPL n'est pas égale au CPL. | |||
X | Le DPL du descripteur de segment de code spécifié est conforme au instruction plus grande que le CPL. | |||
X | Le DPL de l'appel de pont, de tâche de pont, ou le descripteur TSS spécifié par l'instruction est inférieur au CPL ou RPL. | |||
X | Le descripteur de segment spécifié par l'appel de pont ou la tâche de pont est un sélecteur nulle. | |||
X | Le descripteur de segment spécifié par l'appel de pont n'est pas en segment de code en mode legacy pi n'est pas un segment de code 64 bits dans le mode long. | |||
X | Le DPL du du descripteur de segment spécifié par l'appel de pont est plus grand que le CPL. | |||
X | L'appel d'un pont 64 bits avec des bits d'attributs étendues n'est pas à 0. | |||
X | Le TSS du descripteur est présent dans le LDT. | |||
#NP(Segment non présent) | X | L'accès au segment de code, appel d'un pont, tâche de pont, ou TSS n'est pas présent. | ||
#PF(Faute de page) | X | X | Une faute de page résultat de l'exécution de l'instruction | |
#SS(Pile non-canonique) | X | X | X | Une adresse mémoire dépasse la limite du segment de pile ou n'est pas canonique |
#SS(Pile) | X | X | X | Une adresse mémoire dépasse la limite du segment de pile ou n'est pas canonique, et n'est pas l'échange de pile spécifié. |
#SS(Sélecteur) | X | Après l'échange de pile, un accès mémoire dépasse la limite de segment de pile ou est non-canonique. | ||
X | Après l'échange de pile, le registre SS n'est pas chargé avec un sélecteur de segment non-nulle et le segment est marqué comme non-présent. | |||
#TS(Sélecteur TSS invalide) | X | Lors d'une partie de l'échange entre la pile, la destination du segment de la pile ou du registre RSP dans le TSS est en dehors des limites TSS. | ||
X | Lors d'une partie de l'échange entre la pile, la destination du segment de la pile ou du registre RSP dans le TSS est dans un sélecteur nulle. | |||
X | Lors d'une partie de l'échange entre la pile, la destination du sélecteur de pile du bit TI est fixé, mais le sélecteur LDT n'est pas un sélecteur nulle. | |||
X | Lors d'une partie de l'échange entre la pile, la destination du sélecteur de segment de pile dans le TSS est en dehors des limites de la table du descripteur GDT ou LDT. | |||
X | Lors d'une partie de l'échange entre la pile, la destination du sélecteur de segment de pile dans le TSS contient un RPL n'est pas égale au DPL. | |||
X | Lors d'une partie de l'échange entre la pile, la destination du sélecteur de segment de pile dans le TSS contient un DPL n'est pas égale au CPL du sélecteur de segment de code. | |||
X | Lors d'une partie de l'échange entre la pile, la destination du sélecteur de segment de pile dans le TSS n'est pas dans un segment écrivable. | |||
#UD(Opcode invalide) | X | X | X | L'appel long indirect avec le Opcode (FFh /3) est un opérande de registre. |
X | L'appel long direct avec le Opcode (9Ah) est effectué en mode 64 bits. |
Exemples
L'exemple suivant permet d'effectuer un appel de la fin de la commande à + 1Ah en hexadécimal :
- CALL +1A
L'exemple suivant permet d'appeler une adresse absolue 32 bits :
- CALL 01234ABC
L'exemple suivant permet d'appeler une adresse absolue 64 bits :
- CALL 0001234567ABCDEF
L'exemple suivant permet d'appeler la valeur indiqué par le registre EAX :
- CALL EAX
L'exemple suivant permet d'appeler la valeur indiqué par le registre RAX :
- CALL RAX
L'exemple suivant permet d'appeler un symbole définit par l'utilisateur :
- CALL UnSymbole
L'exemple suivant permet d'appeler une étiquette (LABEL) définit par l'utilisateur :
- CALL UnEtiquette
L'exemple suivant permet d'appeler une étiquette proche (LABEL) définit par l'utilisateur :
- CALL SHORT UnEtiquette
L'exemple suivant permet d'appeler une étiquette éloigné (LABEL) définit par l'utilisateur :
- CALL LONG UnEtiquette
L'exemple suivant permet de rappeler l'étiquette précédente la plus proche :
- CALL @b
L'exemple suivant permet de rappeler l'étiquette suivante la plus proche :
- CALL @f
Voici un exemple en Turbo Pascal montrant l'utilisation de cette instruction :
on obtiendra le résultat suivant :
AX = 1Voir également
Langage de programmation - Assembleur 80x86 - Instruction RET
Langage de programmation - Assembleur 80x86 - Instruction RETF
Langage de programmation - Assembleur 80x86 - Instruction RETN
Langage de programmation - Structure de données - Structures récursives linéaires - Pile
Références
Le livre d'Or PC, Martin Althaus, 1992, ISBN: 2-7361-0934-1, page 806
Assembleur Facile, Philippe Mercier, 1990, ISBN: 2-501-01176-7, page 401
AMD64 Architecture Programmer's Manual Volume 3: General-Purpose and System Instructions, Edition Advanced Micro Devices, Revision 3.14, September 2007, Publication No. 24594, page 76 à 83.
Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 2A: Instruction Set Reference, A-M, Edition Intel, Mars 2010, Publication No. 253666-034US, page 168 à 185.