现在的位置: 首页 > 综合 > 正文

IRET/IRETD – 中断返回

2013年10月11日 ⁄ 综合 ⁄ 共 6847字 ⁄ 字号 评论关闭

转自:http://scc.qibebt.cas.cn/docs/optimization/VTune(TM)%20User's%20Guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/instruct32_hh/vc143.htm

http://szkn28szkn.iteye.com/blog/1362460

说明

将程序控制权从异常或中断处理程序返回异常、外部中断或软件生成的中断所中断的程序或过程。这些指令也用于执行从嵌套任务的返回。(使用 CALL 指令启动任务切换时,或是中断、异常导致任务切换到中断或异常程序时,都会创建嵌套任务)。请参阅“IA-32 英特尔(R) 体系结构软件开发人员手册”第 1 卷第 6 章中标题为“任务链接”的部分。

IRET 与 IRETD 是相同操作码的助记符。IRETD 助记符(中断返回双字)用于从使用 32 位操作数大小的中断返回;不过大多数汇编器对这两种操作数大小都互换使用 IRET 助记符。

在“实地址模式”中,IRET 指令执行到中断程序或过程的远返回。在执行此操作的过程中,处理器从堆栈将返回指令指针、返回代码段选择器以及 EFLAGS 映像分别弹入 EIP、CS 以及 EFLAGS 寄存器,然后恢复执行中断的程序或过程。

在“保护模式”中,IRET 指令的操作取决于以下因素:EFLAGS 寄存器中 NT(嵌套任务)与 VM 标志的设置,以及当前堆栈中存储的 EFLAGS 映像中的 VM 标志的设置。根据这些标志的设置,处理器执行以下类型的中断返回:

  • 从虚 8086 模式返回。

  • 返回到虚 8086 模式。

  • 特权级别内返回。特权级别间返回。

  • 从嵌套任务返回(任务切换)。

如果清除 NT 标志(EFLAGS 寄存器),则 IRET 指令执行从中断过程的远返回,而不执行任务切换。返回到的代码段的特权级别必须小于或等于中断处理例程的特权级别(如堆栈弹出的代码段选择器的 PRL 字段所示)。对于实地址模式中断返回,IRET 指令从堆栈将返回指令指针、返回代码段选择器以及 EFLAGS 映像分别弹入 EIP、CS 以及 EFLAGS 寄存器,然后恢复执行中断的程序或过程。如果返回到另一个特权级别,则在恢复程序执行之前,IRET 指令还从堆栈弹出堆栈指针与 SS。如果返回到虚 8086
模式,处理器还从堆栈弹出数据段寄存器。

如果设置 NT 标志,则 IRET 指令从嵌套任务(使用 CALL 指令、中断或异常调用的任务)执行任务切换(返回)到调用或中断的任务。执行 IRET 指令的任务的更新状态保存在它的 TSS 中。如果稍后重新进入该任务,则执行 IRET 指令后面的代码。

操作

IF PE  0
THEN 
GOTO REAL-ADDRESS-MODE:;
ELSE 
GOTO PROTECTED-MODE;
FI;

REAL-ADDRESS-MODE;
IF OperandSize  32
THEN
IF top 12 bytes of stack not within stack limits THEN #SS; FI;
IF instruction pointer not within code segment limits THEN #GP(0); FI;
EIP  Pop();
CS  Pop(); (* 32-bit pop, high-order 16 bits discarded *)
tempEFLAGS  Pop();
EFLAGS  (tempEFLAGS AND 257FD5H) OR (EFLAGS AND 1A0000H);
ELSE (* OperandSize  16 *)
IF top 6 bytes of stack are not within stack limits THEN #SS; FI;
IF instruction pointer not within code segment limits THEN #GP(0); FI;
EIP  Pop();
EIP  EIP AND 0000FFFFH;
CS  Pop(); (* 16-bit pop *)
EFLAGS[15:0]  Pop();
FI;
END;

PROTECTED-MODE:
IF VM  1 (* Virtual-8086 mode: PE=1, VM=1 *)
THEN 
GOTO RETURN-FROM-VIRTUAL-8086-MODE; (* PE=1, VM=1 *)
FI;
IF NT  1
THEN 
GOTO TASK-RETURN;( *PE=1, VM=0, NT=1 *)
FI;
IF OperandSize=32
THEN
IF top 12 bytes of stack not within stack limits
THEN #SS(0)
FI;
tempEIP  Pop();
tempCS  Pop();
tempEFLAGS  Pop();
ELSE (* OperandSize  16 *)
IF top 6 bytes of stack are not within stack limits
THEN #SS(0);
FI;
tempEIP  Pop();
tempCS  Pop();
tempEFLAGS  Pop();
tempEIP  tempEIP AND FFFFH;
tempEFLAGS  tempEFLAGS AND FFFFH;
FI;
IF tempEFLAGS(VM)  1 AND CPL=0
THEN 
GOTO RETURN-TO-VIRTUAL-8086-MODE; 
(* PE=1, VM=1 in EFLAGS image *)
ELSE 
GOTO PROTECTED-MODE-RETURN;
(* PE=1, VM=0 in EFLAGS image *)
FI;

RETURN-FROM-VIRTUAL-8086-MODE: 
(* Processor is in virtual-8086 mode when IRET is executed and stays in virtual-8086 mode *)
IF IOPL=3 (* Virtual mode: PE=1, VM=1, IOPL=3 *)
THEN IF OperandSize  32
THEN
IF top 12 bytes of stack not within stack limits THEN #SS(0); FI;
IF instruction pointer not within code segment limits THEN #GP(0); FI;
EIP  Pop();
CS  Pop(); (* 32-bit pop, high-order 16 bits discarded *)
EFLAGS  Pop();
(*VM,IOPL,VIP,and VIF EFLAGS bits are not modified by pop *)
ELSE (* OperandSize  16 *)
IF top 6 bytes of stack are not within stack limits THEN #SS(0); FI;
IF instruction pointer not within code segment limits THEN #GP(0); FI;
EIP  Pop();
EIP  EIP AND 0000FFFFH;
CS  Pop(); (* 16-bit pop *)
EFLAGS[15:0]  Pop(); (* IOPL in EFLAGS is not modified by pop *)
FI;
ELSE 
#GP(0); (* trap to virtual-8086 monitor: PE=1, VM=1, IOPL<3 *)
FI;
END;

RETURN-TO-VIRTUAL-8086-MODE: 
(* Interrupted procedure was in virtual-8086 mode: PE=1, VM=1 in flags image *)
IF top 24 bytes of stack are not within stack segment limits
THEN #SS(0);
FI;
IF instruction pointer not within code segment limits
THEN #GP(0);
FI;
CS  tempCS;
EIP  tempEIP;
EFLAGS  tempEFLAGS
TempESP  Pop();
TempSS  Pop();
ES  Pop(); (* pop 2 words; throw away high-order word *)
DS  Pop(); (* pop 2 words; throw away high-order word *)
FS  Pop(); (* pop 2 words; throw away high-order word *)
GS  Pop(); (* pop 2 words; throw away high-order word *)
SS:ESP  TempSS:TempESP;
(* Resume execution in Virtual-8086 mode *)
END;

TASK-RETURN: (* PE=1, VM=1, NT=1 *)
Read segment selector in link field of current TSS;
IF local/global bit is set to local
OR index not within GDT limits
THEN #GP(TSS selector); 
FI;
Access TSS for task specified in link field of current TSS;
IF TSS descriptor type is not TSS or if the TSS is marked not busy
THEN #GP(TSS selector); 
FI;
IF TSS not present 
THEN #NP(TSS selector); 
FI;
SWITCH-TASKS (without nesting) to TSS specified in link field of current TSS;
Mark the task just abandoned as NOT BUSY;
IF EIP is not within code segment limit 
THEN #GP(0);
FI;
END;

PROTECTED-MODE-RETURN: (* PE=1, VM=0 in flags image *)
IF return code segment selector is null THEN GP(0); FI;
IF return code segment selector addrsses descriptor beyond descriptor table limit 
THEN GP(selector; FI;
Read segment descriptor pointed to by the return code segment selector
IF return code segment descriptor is not a code segment THEN #GP(selector); FI;
IF return code segment selector RPL < CPL THEN #GP(selector); FI;
IF return code segment descriptor is conforming
AND return code segment DPL > return code segment selector RPL
THEN #GP(selector); FI;
IF return code segment descriptor is not present THEN #NP(selector); FI:
IF return code segment selector RPL > CPL 
THEN GOTO RETURN-OUTER-PRIVILEGE-LEVEL;
ELSE GOTO RETURN-TO-SAME-PRIVILEGE-LEVEL
FI;
END;

RETURN-TO-SAME-PRIVILEGE-LEVEL: (* PE=1, VM=0 in flags image, RPL=CPL *)
IF EIP is not within code segment limits THEN #GP(0); FI;
EIP  tempEIP;
CS  tempCS; (* segment descriptor information also loaded *)
EFLAGS (CF, PF, AF, ZF, SF, TF, DF, OF, NT)  tempEFLAGS;
IF OperandSize=32
THEN
EFLAGS(RF, AC, ID)  tempEFLAGS;
FI;
IF CPL  IOPL
THEN
EFLAGS(IF)  tempEFLAGS;
FI;
IF CPL  0
THEN
EFLAGS(IOPL)  tempEFLAGS;
IF OperandSize=32
THEN EFLAGS(VM, VIF, VIP)  tempEFLAGS;
FI;
FI;
END;

RETURN-TO-OUTER-PRIVILGE-LEVEL:
IF OperandSize=32
THEN
IF top 8 bytes on stack are not within limits THEN #SS(0); FI;
ELSE (* OperandSize=16 *)
IF top 4 bytes on stack are not within limits THEN #SS(0); FI;
FI;
Read return segment selector;
IF stack segment selector is null THEN #GP(0); FI;
IF return stack segment selector index is not within its descriptor table limits
THEN #GP(SSselector); FI;
Read segment descriptor pointed to by return segment selector;
IF stack segment selector RPL  RPL of the return code segment selector
IF stack segment selector RPL  RPL of the return code segment selector
OR the stack segment descriptor does not indicate a writable data segment;
OR stack segment DPL  RPL of the return code segment selector
THEN #GP(SS selector); 
FI;
IF stack segment is not present THEN #SS(SS selector); FI;
IF tempEIP is not within code segment limit THEN #GP(0); FI;
EIP  tempEIP;
CS  tempCS;
EFLAGS (CF, PF, AF, ZF, SF, TF, DF, OF, NT)  tempEFLAGS;
IF OperandSize=32
THEN
EFLAGS(RF, AC, ID)  tempEFLAGS;
FI;
IF CPL  IOPL
THEN
EFLAGS(IF)  tempEFLAGS;
FI;
IF CPL  0
THEN
EFLAGS(IOPL)  tempEFLAGS;
IF OperandSize=32
THEN EFLAGS(VM, VIF, VIP)  tempEFLAGS;
FI;
FI;
CPL  RPL of the return code segment selector;
FOR each of segment register (ES, FS, GS, and DS)
DO;
IF segment register points to data or non-conforming code segment
AND CPL > segment descriptor DPL (* stored in hidden part of segment register *)
THEN (* segment register invalid *)
SegmentSelector  0; (* null segment selector *)
FI;
OD;
END:

 

影响的标志

根据处理器的操作模式,可能会修改 EFLAGS 寄存器中的所有标志与字段。如果执行从嵌套任务到前一项任务的返回,则根据前一项任务的 TSS 存储的 EFLAGS 映像修改 EFLAGS 寄存器。

保护模式异常

#GP(0) - 如果返回代码或堆栈段选择器为空。如果返回指令指针超出返回代码段限制。

#GP(选择器) - 如果段选择器索引超出描述符表格限制。如果返回代码段选择器 RPL 大于 CPL。如果相容代码段的 DPL 大于返回代码段选择器的 RPL。如果非相容代码段的 DPL 不等于代码段选择器的 RPL。如果堆栈段描述符的 DPL 不等于返回代码段选择器的 RPL。如果堆栈段不是可写的数据段。如果堆栈段选择器 RPL 不等于返回代码段选择器的 RPL。如果代码段的段描述符未指明它是代码段。如果 TSS 的段选择器将自己的局部/全局位设置为局部。如果 TSS 段描述符指出 TSS 忙或不可用。

#SS(0) - 如果堆栈的栈顶字节超出堆栈限制。

#NP(选择器) - 如果返回代码或堆栈段不存在。

#PF(错误代码) - 如果发生页错误。

#AC(0) - 如果在 CPL 是 3 且启用对齐检查的情况下发生未对齐的内存引用。

实地址模式异常

#GP - 如果返回指令指针超出返回代码段限制。

#SS - 如果堆栈的栈顶字节超出堆栈限制。

虚 8086 模式异常

#GP(0) - 如果返回指令指针超出返回代码段限制。如果 IOPL 不等于 3。

#PF(错误代码) - 如果发生页错误。

#SS(0) - 如果堆栈的栈顶字节超出堆栈限制。

#AC(0) - 如果在启用对齐检查的情况下进行未对齐的内存引用。

 

抱歉!评论已关闭.