组装中的指令STI,RET和IRET之间有什么区别



所以在汇编中,STI启用中断,RET从堆栈中获取一个数字并将其放入IP中,并在指令[IP]时恢复执行。IRET可以同时做到这两点,对吧?那为什么我不能只使用STI和RET?或者我可以随时使用 IRET?

iret

很复杂 - 它的行为取决于许多因素(CPU模式,返回信息等(,在某些情况下,它可能会执行完整的硬件任务切换(更改每个通用寄存器和CR3/虚拟地址空间(。

最简单的iret将从堆栈中加载 CS、IP/EIP/RIP 和 FLAGS/EFLAG;但通常它也加载 SS 和 SP/ESP/RSP;所有段寄存器负载(CS、SS(都会导致 GDT 或 LDT 查找和保护检查(这会增加开销(。

另请注意,加载 FLAGS/EFLAGS 会恢复其以前的值。如果在中断处理程序启动之前禁用了可屏蔽的中断(对于软件中断和异常是可能的(,则堆栈上保存的 FLAGS/EFLAG 将具有"中断标志清除",IRET将恢复"中断标志清除",并且不会导致"中断标志设置"。

ret仅从堆栈加载 IP/EIP/RIP。它不加载CS或FLAGS/EFLAGS。

sti不会加载 FLAGS/EFLAGS,只设置一位,这包括不恢复所有其他标志(例如 carry、溢出等(。这可能是一个极其重要的区别(例如,您不希望 IRQ 在未知/随机时间丢弃算术标志并导致到处都出现不可预测的故障(。

这意味着sti然后ret与(最简单的(IRET非常不同 - 它的作用要少得多,行为(涉及FLAGS/EFLAGS(非常不同。

模拟iret行为的最接近的序列是popf(将 FLAGS/EFLAGS 恢复到其以前的值(,然后是retf(加载 CS 和 IP/EIP/RIP(;这可能具有相同的复杂行为(例如,可能会或可能不会导致权限级别更改,可能会导致也可能不会导致硬件任务切换(。

但是; 即使在这种"尽可能接近 IRET"的情况下,它也不一样,因为 2 个单独的指令是分开的 - 存在 IRQ 在popf之后但在retf之前发生的风险。

最新更新