因此在汇编中,STI 启用中断,RET 从堆栈中取出一个数字并将其放入 IP 中,并在指令 [IP] 处恢复执行。IRET 两者兼而有之,对吗?那么为什么我不能使用 STI 和 RET 来代替呢?或者我可以一直使用 IRET 吗?
iret很复杂 - 它的行为取决于很多因素(CPU 模式、返回信息等),并且在某些情况下它可能会执行完整的硬件任务切换(更改每个通用寄存器和 CR3/虚拟地址空间)。
最简单的可能iret是从堆栈加载 CS、IP/EIP/RIP 和 FLAGS/EFLAGS;但通常它也会加载 SS 和 SP/ESP/RSP;所有段寄存器加载(CS、SS)都会导致 GDT 或 LDT 查找和保护检查(这会增加开销)。
另请注意,加载 FLAGS/EFLAGS 会恢复其先前的值。如果在中断处理程序启动之前禁用可屏蔽中断(这对于软件中断和异常来说是可能的),则保存在堆栈上的 FLAGS/EFLAGS 将具有“中断标志清除”并且将恢复IRET“中断标志清除”并且将不会导致“中断标志设置”。
ret仅从堆栈加载 IP/EIP/RIP。它不加载 CS 或 FLAGS/EFLAGS。
sti不加载 FLAGS/EFLAGS 并且只设置一位,这包括不恢复所有其他标志(例如进位、溢出等)。这可能是一个极其重要的区别(例如,您不希望 IRQ 在未知/随机时间丢弃算术标志并在各处导致不可预测的故障)。
这意味着stithenret与(最简单的)非常不同IRET- 它的作用要少得多,而且行为(涉及 FLAGS/EFLAGS)也非常不同。
模拟行为的最接近的顺序iret是popf(将 FLAGS/EFLAGS 恢复为其之前的值),然后retf(加载 CS 和 IP/EIP/RIP);并且这可能具有相同的复杂行为(例如,可能会或可能不会导致特权级别改变,可能会或可能不会导致硬件任务切换)。
然而; 即使在这种“尽可能接近 IRET”的情况下,它也是不一样的,因为 2 个单独的指令是分开的 - 存在 IRQ 在 后面但之前发生的popf风险retf。
| 归档时间: |
|
| 查看次数: |
5021 次 |
| 最近记录: |