【计算机系统结构】near return instructions 近返回 。Far return instructions 远程返回指令

Opcode Mnemonic Description
C3 RET Near return to calling procedure.
CB RET Far return to calling procedure.
C2 iw RET imm16 Near return to calling procedure and pop imm16 bytes from stack.
CA iw RET imm16 Far return to calling procedure and pop imm16 bytes from stack.

将程序控制转移到位于堆栈顶部的返回地址。 地址通常由CALL指令放在堆栈上,并返回到CALL指令后面的指令。

可选的源操作数指定弹出返回地址后要释放的堆栈字节数; 默认值为none。 此操作数可用于从堆栈中释放传递给被调用过程且不再需要的参数。 当用于切换到新过程的CALL指令使用具有非零字数的调用门来访问新过程时,必须使用它。 这里,RET指令的源操作数必须指定与调用门的字计数字段中指定的字节数相同的字节数。

The RET instruction can be used to execute three different types of returns:

Near return
A return to a calling procedure within the current code segment (the segment currently pointed to by the CS register), sometimes referred to as an intrasegment return.
Far return
A return to a calling procedure located in a different segment than the current code segment, sometimes referred to as an intersegment return.
Inter-privilege-level far return
A far return to a different privilege level than that of the currently executing program or procedure.

当执行近返回时,处理器将返回指令指针(偏移)从堆栈顶部弹出到EIP寄存器,并在新指令指针处开始执行程序。 CS寄存器保持不变。

执行远程返回时,处理器将返回指令指针从堆栈顶部弹出到EIP寄存器,然后将段顶选择器从堆栈顶部弹出到CS寄存器中。然后,处理器在新指令指针的新代码段中开始程序执行。

除了处理器检查代码的特权级别和访问权限以及返回的堆栈段以确定是否允许进行控制转移之外,特权级别远程返回的机制类似于段间返回。如果DS,ES,FS和GS段寄存器在特权级别返回期间被清除,则它们将引用不允许在新特权级别访问的段。由于堆栈切换也发生在特权级别返回上,因此ESP和SS寄存器从堆栈加载。

如果在特权级别调用期间将参数传递给被调用过程,则必须将可选的源操作数与RET指令一起使用以释放返回的参数。

这里,参数从被调用过程的堆栈和调用过程的堆栈(即返回的堆栈)中释放。

switch(Instruction) {
	case NearReturn:
		if(OperandSize == 32 && !IsWithinStackLimits(TopStackBytes(12))) Exception(SS(0)); //top 12 bytes of stack not within stack limits
		//OperandSize == 16
		else if(!IsWithinStackLimits(TopStackBytes(6)) Exception(SS(0)); //IF top 6 bytes of stack not within stack limits
		TemporaryEIP = Pop();
		TemporaryEIP = TemporaryEIP & 0xFFFF;
		if(!IsWithinCodeSegmentLimits(TemporaryEIP)) Exception(GP(0));
		EIP = TemporaryEIP;
		if(HasImmediateOperand()) { //instruction has immediate operand
			if(StackAddressSize == 32) ESP = ESP + Source; //release parameters from stack
			//StackAddressSize == 16
			else SP = SP + Source; //release parameters from stack
		}
		break;
	case FarReturn:
		//Real-address mode or virtual-8086 mode
		if(PE == 0 || (PE == 1 && VM == 1)) {
			if(OperandSize == 32) {
				if(!IsWithinStackLimits(TopStackBytes(12)) Exception(SS(0)); //top 12 bytes of stack not within stack limits
				EIP = Pop();
				CS = Pop(); //32-bit pop, high-order 16 bits discarded
			}
			else { //OperandSize == 16
				if(!IsWithinStackLimits(TopStackBytes(6)) Exception(SS(0)); //top 6 bytes of stack not within stack limits
				TemporaryEIP = Pop();
				TemporaryEIP = TemporaryEIP & 0xFFFF;
				if(!IsWithinCodeSegmentLimits(TemporaryEIP)) Exception(GP(0));
				EIP = TemporaryEIP;
				CS = Pop(); //16-bit pop
			}
			if(HasImmediateOperand()) else SP = SP + Source; //instruction has immediate operand; release parameters from stack
		}
		//Protected mode, not virtual-8086 mode
		else if(PE == 1 && VM == 0) {
			if(OperandSize == 32 && !IsWithinStackLimits(OffsetStackBytes(4, 4)) Exception(SS(0)); //second doubleword on stack is not within stack limits
			//OperandSize == 16
			else if(!IsWithinStackLimits(OffsetStackBytes(2, 2))) Exception(SS(0)); //second word on stack is not within stack limits
			if(ReturnCode.SegmentSelector == 0) Exception(GP(Selector));
			if(!IsWithinDescriptorTableLimits(ReturnCode.SegmentSelector)) Exception(GP(Selector));
			ReturnCode.SegmentDescriptor = ObtainSegmentDescriptor(); //Obtain descriptor to which return code segment selector points from descriptor table
			if(!IsCodeSegment(ReturnCode.SegmentDescriptor)) Exception(GP(Selector));
			if(ReturnCode.SegmentSelector.RPL < CPL) Exception(GP(Selector));
			if(IsConforming(ReturnCode.SegmentDescriptor && ReturnCode.Segment.DPL > ReturnCode.SegmentSelector.RPL) Exception(GP(Selector));
			if(!IsPresent(ReturnCode.SegmentDescriptor)) Exception(NP(Selector));
			if(ReturnCode.SegmentSelector.RPL > CPL) {
				//Return outer privilege level
				if(OperandSize == 32 && !IsWithinStackLimits(TopStackBytes(16 + Source)) Exception(SS(0)); //top 16 + Source bytes of stack not within stack limits
				//OperandSize == 16
				else if(!IsWithinStackLimits(TopStackBytes(8 + Source)) Exception(SS(0)); //top 8 + Source bytes of stack not within stack limits
				ReturnSegmentSelector = ReadReturnSegmentSelector();
				if(StackSegmentSelector == 0) Exception(GP(0));
				if(!IsWithinDescriptorTableLimits(ReturnStack.SegmentSelector.Index)) Exception(GP(Selector));
				if(StackSegmentSelector.RPL != ReturnCode.SegmentSelector.RPL || !IsWritableDataSegment(StackSegment) || StackSegmentDescriptor.DPL != ReturnCode.SegmentSelector.RPL) Exception(GP(Selector));
				if(!IsPresent(StackSegment)) Exception(SS(StackSegmentSelector));
				if(!IsWithinLimits(ReturnCode.SegmentLimit, ReturnInstructionPointer)) Exception(GP(0));
				CPL = ReturnCode.SegmentSelector.RPL;
				if(OperandSize == 32) {
					EIP = Pop();
					CS = Pop(); //32-bit pop, high-order 16 bits discarded; segment descriptor information also loaded
					CS.RPL = CPL;
					ESP = ESP + Source; //release parameters from called procedure's stack
					TemporaryESP = Pop();
					TemporarySS = Pop(); //32-bit pop, high-order 16 bits discarded; segment descriptor information also loaded
					ESP = TemporaryESP;
					SS = TemporarySS;
				}
				//OperandSize == 16
				else {
					EIP = Pop();
					EIP = EIP & 0xFFFF;
					CS = Pop(); //16-bit pop; segment descriptor information also loaded
					CS.RPL = CPL;
					ESP = ESP + Source; //release parameters from called procedure's stack
					TemporaryESP = Pop();
					TemporarySS = Pop(); //16-bit pop; segment descriptor information also loaded
					ESP = TemporaryESP;
					SS = TemporarySS;
				}
				SegmentRegisters[] = {ES, FS, GS, DS};
				while(SegmentRegister = NextSegmentRegister(SegmentRegisters)) {
					if(IsDataPointer(SegmentRegister)  || !IsConformingCodeSegment(SegmentRegister) && CPL > SegmentDescriptor.DPL /*DPL in hidden part of segment register*/) SegmentSelector = 0; //segment register is invalid, null segment selector
					if(!IsWithinDescriptorTableLimits(SegmentSelector.Index) || (!IsData(SegmentDescriptor) && !IsReadableCodeSegment(SegmentDescriptor)) || (IsData(SegmentDescriptor) && !IsConformingCodeSegment(SegmentDescriptor) && SegmentDescriptor.DPL < CPL && SegmentDescriptor.DPL < CodeSegment.SegmentSelector.RPL)) SegmentSelectorRegister = NullSelector;
					ESP = ESP + Source; //release parameters from called procedure's stack
				}
			}
			else {
				//Return to same privilege level
				if(!IsWithinLimits(ReturnCode.SegmentLimit, ReturnInstructionPointer)) Exception(GP(0));
				if(OperandSize == 32) {
					EIP = Pop();
					CS = Pop(); //32-bit pop, high-order 16 bits are discarded
					ESP = ESP + Source; //Release parameters from stack
				}
				else { //OperandSize == 16
					EIP = Pop();
					EIP = EIP & 0xFFFF;
					ESP = ESP + Source; //Release parameters from stack
				}
			}
		}
		break;
}

参考 https://c9x.me/x86/html/file_module_x86_id_280.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值