如果CPU获取指令,EIP==CR2是否可能?
我只是想知道,但经过多次搜索,似乎没有人关心它。
页面故障将CR2设置为页面故障线性地址,但它会保持其值,直到下一个页面故障。
在页面错误得到解决并且页面错误处理程序返回到用户空间后,它将重新运行出错指令。发生这种情况的正常方式是通过iret
,它将CS:EIP设置为异常返回地址,。
如果页面错误发生在代码提取上,并且您有一个平面内存模型(CS base=0,因此EIP=线性地址(,那么CR2=出错指令的地址,这也是#PF异常推送的异常返回地址。
一个混淆因素是在指令执行期间,EIP是当前指令末尾的地址。(相对跳转和[rip + rel32]
寻址模式是相对于指令末尾的。(但是如果您想到指令之间的逻辑状态,例如在iret
设置新的CS:EIP之后,但在获取指令+解码指令之前,EIP再次发生更改,那么在正常操作期间,您可以使EIP=CR2,而不必执行mov cr2, eax
,这当然会简单地创建您想要的任何条件。
当然,这只是逻辑执行模型,按照程序顺序一次运行一条指令。也许像386这样的非流水线CPU实际上可以有这样的物理状态,但现代超标量无序执行CPU只会保持一种运行的错觉,就好像他们已经做到了一样。
假设您有类似的内存布局
0x401234 jmp foo
...
0x402000 foo: nop # in an page that's not mapped yet
一个可能的执行顺序可能是:
- CR2=未知,EIP=0x401234
jmp foo
- CR2=未知,EIP=0x402000(未映射页面(
- CR2=0x402000,EIP=#PF处理程序的顶部(从IDT条目加载(
- 页面故障处理器将页面连接到HW页面表中;假设它已经在RAM中,或者在等待I/O或从zram解压缩后
- CR2=0x402000,EIP=#PF处理程序结束,
iret
- CR2=0x402000、EIP=0x402000,右在该
iret
之后,开始执行nop
之前 - CR2=0x402000,EIP=0x402001,在执行
nop
期间,以及在执行之后的任何操作之前