Retour à l'accueil | Contact : etienne"point"sauvage"at"gmail.com | Retour à la liste des instructions. |
CALL (Far) | Far procedure CALLappel de procédure distante |
Pousse les informations de lien vers une procédure sur la pile et dérive vers l'adresse cible, qui contient la première instruction de la procédure appelée. L'opérande définit le sélecteur et l'offset de la cible.
L'instruction peut spécifier la cible directement en intégrant le pointeur distant dans l'opcode du CALL (Far), ou indirectement en référençant un pointeur distant en mémoire. En mode 64 bits, les seuls appels distants autorisés sont les indirects, l'exécution d'un appel distant direct (opcode 9A) générant une exception d'opcode indéfini.
Le sélecteur de la cible utilisé par l'instruction peut être un sélecteur de code dans tous les modes. De plus, le sélecteur de cible peut référencer une porte d'appel en mode protégé, ou une porte de tâche ou un sélecteur TSS en mode protégé compatible.
La cible est un sélecteur de code-Le CS:rIP de l'instruction suivante est poussé sur la pile en utilisant des poussées de la taille de l'opérande. Ensuite, le code du CS:rIP cible est exécuté. Dans ce cas, le décalage de la cible ne peut être qu'une valeur sur 16 ou 32 bits, en fonction de la taille de l'opérande, et est complété par des zéros jusqu'à 64 bits. On ne permet pas le changement de niveau de privilège.
La cible est une porte d'appel-La porte d'appel spécifie le segment et le décalge effectifs de la cible. Les portes d'appel autorisent les appels vers du code aussi ou plus privilégié. Si le segment cible est au même niveau de privilège que le segment de code courant, le CS:rIP de la prochaine instruction est opussé sur la pile.
Si le CALL (Far) change le niveau de privilège, alors un changement de pile intervient, en utilisant un pointeur de pile issu d'un niveau intérieur du TSS. Le CS:rIP de l'instruction suivante est poussé sur cette nouvelle pile. Si on est en mode compatibilité et que le champ nombre de paramètres de la porte d'appel n'est pas zéro, alors jusqu'à 31 opérandes sont copiés de la pile de l'appelant vers la nouvelle pile. Enfin, le SS:rSP de l'appelant est poussé sur la nouvelle pile.
Quand l'appel est fait en passant par une porte d'appel, les poussées sur la pile sont de 16, 32 ou 64 bits, en fonction de la taille de la porte d'appel. La taille du rIP de la cible sera pareillement de 16, 32 ou 64 bits, en fonction de la taille de la porte d'appel. Si le rIP de la pile est plus petit que 64 bits, il est complété par des zéros jusqu'à 64 bits. Le mode long n'autorise que les portes d'appel de 64 bits, qui doivent pointer vers des segments de code de 64 bits.
La cible est une porte de tâche ou un TSS-Si on est en compatibilité mode protégé, alors un changement de tâche a lieu. Consultez "Gestionnaire des tâches matériel en mode compatible" du volume 2 pour plus d'information à propos des changements de tâche. Les changements de tâche matériels ne sont plus supportés en mode long.
Consultez CALL (Near) pour les informations concernant les appels proches - appels à des procédures localisées dans le segment de code courant. Pour plus d'information à propos des instructions de controle de flux, consultez "Transferts de contrôle" dans le volume 1 et "Vérifications des privilèges de transfert de contrôle" dans le volume 2.
Mnémonique | Opcode | Description |
CALL FARpntr16:16 | 9A cd | Appel distant direct, avec la cible spécifiée par un pointeur distant contenu dans l'instruction. (Non valide en mode 64 bits.) |
CALL FARpntr16:32 | 9A cp | Appel distant direct, avec la cible spécifiée par un pointeur distant contenu dans l'instruction. (Non valide en mode 64 bits.) |
CALL FARmem16:16 | FF /3 | Appel distant indirect, avec la cible spécifiée par un pointeur distant en mémoire. |
CALL FARmem16:32 | FF /3 | Appel distant indirect, avec la cible spécifiée par un pointeur distant en mémoire. |
// Consultez "Définitions du Pseudo-code" page 48. CALLF_START: IF (REAL_MODE) CALLF_REAL_OR_VIRTUAL ELSIF (PROTECTED_MODE) CALLF_PROTECTED ELSE // (VIRTUAL_MODE) CALLF_REAL_OR_VIRTUAL CALLF_REAL_OR_VIRTUAL: IF (OPCODE = callf [mem]) // CALLF Indirect { temp_RIP = READ_MEM.z [mem] temp_CS = READ_MEM.w [mem+Z] } ELSE // (OPCODE = callf direct) { temp_RIP = z-sized offset specified in the instruction zero-extended to 64 bits temp_CS = selector specified in the instruction } PUSH.v old_CS PUSH.v next_RIP IF (temp_RIP>CS.limit) EXCEPTION [#GP(0)] CS.sel = temp_CS CS.base = temp_CS SHL 4 RIP = temp_RIP EXIT CALLF_PROTECTED: IF (OPCODE = callf [mem]) //CALLF Indirect { temp_offset = READ_MEM.z [mem] temp_sel = READ_MEM.w [mem+Z] } ELSE // (OPCODE = callf direct) { IF (64BIT_MODE) EXCEPTION [#UD] // 'CALLF direct' is illegal in 64-bit mode. temp_offset = z-sized offset specified in the instruction zero-extended to 64 bits temp_sel = selector specified in the instruction } temp_desc = READ_DESCRIPTOR (temp_sel, cs_chk) IF (temp_desc.attr.type = 'available_tss') TASK_SWITCH // Using temp_sel as the target TSS selector. ELSIF (temp_desc.attr.type = 'taskgate') TASK_SWITCH // Using the TSS selector in the task gate // as the target TSS. ELSIF (temp_desc.attr.type = 'code') // If the selector refers to a code descriptor, then // the offset we read is the target RIP. { temp_RIP = temp_offset CS = temp_desc PUSH.v old_CS PUSH.v next_RIP IF ((!64BIT_MODE) && (temp_RIP > CS.limit)) // temp_RIP can't be non-canonical because EXCEPTION [#GP(0)] // it's a 16- or 32-bit offset, zero-extended // to 64 bits. RIP = temp_RIP EXIT } ELSE // (temp_desc.attr.type = 'callgate') // If the selector refers to a call gate, then // the target CS and RIP both come from the call gate. { IF (LONG_MODE) // The size of the gate controls the size of the stack pushes. V=8-byte // Long mode only uses 64-bit call gates, force 8-byte opsize. ELSIF (temp_desc.attr.type = 'callgate32') V=4-byte // Legacy mode, using a 32-bit call-gate, force 4-byte opsize ELSE // (temp_desc.attr.type = 'callgate16') V=2-byte // Legacy mode, using a 16-bit call-gate, force 2-byte opsize. temp_RIP = temp_desc.offset IF (LONG_MODE) // In long mode, we need to read the 2nd half of a // 16-byte call-gate from the GDT/LDT, to get the upper // 32 bits of the target RIP. { temp_upper = READ_MEM.q [temp_sel+8] IF (temp_upper's extended attribute bits != 0) EXCEPTION [#GP(temp_sel)] temp_RIP = tempRIP + (temp_upper SHL 32) // Concatenate both halves of RIP } CS = READ_DESCRIPTOR (temp_desc.segment, clg_chk) temp_CPL = CS.sel.rpl IF (CPL=temp_CPL) { PUSH.v old_CS PUSH.v next_RIP IF ((64BIT_MODE) && (temp_RIP is non-canonical) || (!64BIT_MODE) && (temp_RIP > CS.limit)) { EXCEPTION[#GP(0)] } RIP = temp_RIP EXIT } ELSE // (CPL != temp_CPL), Changing privilege level. { CPL = temp_CPL temp_ist = 0 // Call-far doesn't use ist pointers. temp_SS_desc:temp_RSP = READ_INNER_LEVEL_STACK_POINTER (CPL, temp_ist) RSP.q = temp_RSP SS = temp_SS_desc PUSH.v old_SS // #SS on this and following pushes use // SS.sel as error code. PUSH.v old_RSP IF (LEGACY_MODE) // Legacy-mode call gates have { // a param_count field. temp_PARAM_COUNT = temp_desc.attr.param_count FOR (I=temp_PARAM_COUNT; I>0; I--) { temp_DATA = READ_MEM.v [old_SS:(old_RSP+I*V)] PUSH.v temp_DATA } } PUSH.v old_CS PUSH.v next_RIP IF ((64BIT_MODE) && (temp_RIP is non-canonical) || (!64BIT_MODE) && (temp_RIP > CS.limit)) { EXCEPTION [#GP(0)] } RIP = temp_RIP EXIT } }Instructions apparentées
CALL (Near), RET (Near), RET (Far)
rFLAGS affectés
Aucun, sauf si un changement de tâche a lieu, auquel cas tous les drapeaux sont modifiés.
Exceptions
Exception | Réel | 8086 virtuel | Protégé | Cause de l'exception |
Opcode non valide, #UD | X | X | X | L'opcode du CALL distant indirect (FF /3) avait un opérande de regsitre. | X | L'opcode du CALL distant direct (9A) a été exécuté en mode 64 bits. |
TSS non valide, #TS (sélecteur) | X | En tant que partie d'un changement de pile, le sélecteur de segment de pile ciblé ou rSP du TSS était au-delà de la limite de TSS. | X | En tant que partie d'un changement de pile, le sélecteur de segment de la pile ciblée dans le TSS était un sélecteur nul. | X | En tant que partie d'un changement de pile, le bit TI du sélecteur de la pile ciblée était positionné, mais le sélecteur LDT était un sélecteur nul. | X | En tant que partie d'un changement de pile, le sélecteur de segment de la pile ciblée dans le TSS était au-delà de la limite du TGD (GDT) ou du TLD (LDT). | X | En tant que partie d'un changement de pile, le sélecteur de segment de la pile ciblée dans le TSS contenait un RPL qui n'était pas égal à son DPL. | X | En tant que partie d'un changement de pile, le sélecteur de segment de la pile ciblée dans le TSS contenait un DPL qui n'était pas égal au niveau de privilège courant du sélecteur de segment de code. | X | En tant que partie d'un changement de pile, le sélecteur de segment de la pile ciblée dans le TSS n'était pas un segment inscriptible. |
Segment absent, #NP (selector) | X | Le segment de code, la porte d'appel ou de tâche, ou le TSS était absent. | ||
Pile, #SS | X | X | X | Une adresse mémoire a dépassé la limite du segment de pile ou était non canonique, et aucun changement de pile n'a eu lieu. |
Pile, #SS | X | Après un changement de pile, un accès à la mémoire a dépassé la limite du segment de pile ou était non canonique. | X | En tant que partie d'un changement de pile, le registre SS a été chargé avec un sélecteur de segment non nul et le segment a été marqué absent. |
Protection générale, #GP | X | X | X | Une adresse mémoire a dépassé la limite d'un segment de données ou était non canonique. | X | X | X | Le décalage ciblé a fait dépasser la limite du segment de code ou était non canonique. | X | Un segment de données NULL a été utilisé pour référencer la mémoire. |
Protection générale, #GP (selector) | X | Le sélecteur de segment de code ciblé était un sélecteur nul. | X | Le segment de code, la porte d'appel ou de tâche, ou le descripteur TSS a dépassé la limite du tableau des descripteurs. | X | Le bit TI d'un sélecteur de segment était positionné, mais le sélecteur LDT était un sélecteur nul. | X | Le descripteur de segment spécifié par l'instruction n'était ni un segment de code, une porte d'appel ou de tâche, ni un TSS disponible en mode compatible, ni un segment de code de 64 bits ou une porte d'appel de 64 bits en mode long. | X | Le RPL du sélecteur du segment de code non conforme spécifié par l'instruction était plus grand que le niveau de privilège courant, ou bien son DPL n'était pas égal au niveau de privilège courant. | X | Le DPL du descripteur du segment de code conforme spécifié par l'instruction était supérieur au niveau de privilège courant. | X | Le bit TI d'un sélecteur de segment était positionné, mais le sélecteur LDT était un sélecteur nul. | X | Le bit TI d'un sélecteur de segment était positionné, mais le sélecteur LDT était un sélecteur nul. | X | Le bit TI d'un sélecteur de segment était positionné, mais le sélecteur LDT était un sélecteur nul. |
Faute de page, #PF | X | X | Une faute de page a résulté de l'exécution de l'instruction. | |
Vérification d'alignement, #AC | X | X | Une référence mémoire non alignée a été faite pendant que la vérification d'alignement était active. |
Source : AMD x86-64 Architecture PROGRAMMER'S MANUAL Volume 3 General-Purpose and System Instructions, 24594 Rev. 3.02 August 2002.
Retour à l'accueil | Contact : etienne"point"sauvage"at"gmail.com | Retour à la liste des instructions |