Retour à l'accueil Contact : etienne"point"sauvage"at"gmail.com Retour à la liste des instructions.

CALL (Far)

Far procedure CALL


appel 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.

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émoniqueOpcodeDescription
CALL FARpntr16:169A cdAppel distant direct, avec la cible spécifiée par un pointeur distant contenu dans l'instruction. (Non valide en mode 64 bits.)
CALL FARpntr16:329A cpAppel distant direct, avec la cible spécifiée par un pointeur distant contenu dans l'instruction. (Non valide en mode 64 bits.)
CALL FARmem16:16FF /3Appel distant indirect, avec la cible spécifiée par un pointeur distant en mémoire.
CALL FARmem16:32FF /3Appel distant indirect, avec la cible spécifiée par un pointeur distant en mémoire.

Action

// 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

ExceptionRéel8086
virtuel
ProtégéCause de l'exception
Opcode non valide, #UDXXXL'opcode du CALL distant indirect (FF /3) avait un opérande de regsitre.
XL'opcode du CALL distant direct (9A) a été exécuté en mode 64 bits.
TSS non valide, #TS (sélecteur)XEn 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.
XEn 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.
XEn 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.
XEn 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).
XEn 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.
XEn 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.
XEn 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)XLe segment de code, la porte d'appel ou de tâche, ou le TSS était absent.
Pile, #SSXXXUne 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, #SSXAprès un changement de pile, un accès à la mémoire a dépassé la limite du segment de pile ou était non canonique.
XEn 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, #GPXXXUne adresse mémoire a dépassé la limite d'un segment de données ou était non canonique.
XXXLe décalage ciblé a fait dépasser la limite du segment de code ou était non canonique.
XUn segment de données NULL a été utilisé pour référencer la mémoire.
Protection générale, #GP (selector)XLe sélecteur de segment de code ciblé était un sélecteur nul.
XLe segment de code, la porte d'appel ou de tâche, ou le descripteur TSS a dépassé la limite du tableau des descripteurs.
XLe bit TI d'un sélecteur de segment était positionné, mais le sélecteur LDT était un sélecteur nul.
XLe 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.
XLe 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.
XLe DPL du descripteur du segment de code conforme spécifié par l'instruction était supérieur au niveau de privilège courant.
XLe bit TI d'un sélecteur de segment était positionné, mais le sélecteur LDT était un sélecteur nul.
XLe bit TI d'un sélecteur de segment était positionné, mais le sélecteur LDT était un sélecteur nul.
XLe bit TI d'un sélecteur de segment était positionné, mais le sélecteur LDT était un sélecteur nul.
Faute de page, #PFXXUne faute de page a résulté de l'exécution de l'instruction.
Vérification d'alignement, #ACXXUne 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