- 论坛徽章:
- 0
|
在CPU与编译器版有位网友提出了lmsw %eax之后一个长跳转重新装在CS及eip. 这貌似是看到的bootloader中的惯例. 我以前也只是这样想当然的按照这种方式来做。
并没有想其中的细节。 提出的问题就是: 在置PE标志位之后.处理器处于保护模式. 之后一切所有的规则都得按照保护模式的那一套来做。这里涉及到的就是寻址方式。
常跳转的指令以及操作数是如何获取的? 因为在处理器切换到保护模式之后,CS还没有重新加载,即使重新加载,那么重新加载CS的指令和操作数又是如何获取的呢? 这貌似是
先有鸡还是先有蛋的问题... 有网友说是预取指。可是我实验了一下,验证这个是错误的解释。 代码很简单。
- #say goodbye to the real mode...
- movw $0x0001, %ax
- lmsw %ax
- jmp flush_instr /* 这样能够刷新预取指令队列吧? */
- flush_instr:
- pushl %eax
- pushl %ebx
- pushl %ecx
- pushl %edx
- popl %edx
- popl %ecx
- popl %ebx
- popl %eax
- jmp flush_instr
复制代码 可以正常的执行... 最后肯定会异常的...呵呵...
我来说说我的观点。
首先需要提到的就是段寄存器中的非可能编程的所谓的影子寄存器。在实模式下这个影子寄存器应该也是可用的.只是不能对它编程。
因为实模式的寻址方式是seg << 4 + off。这个当然与影子寄存器的值是无关的。假设这个影子寄存器中的基址应该是seg << 4,至于段长无法推测.
如果需要起作用的话,至少是64KB。有了这个假设,从实模式到保护模式切换的那一刻一切都有很好的解释了.
切换到保护模式.将机器状态字的最低比特位置1即可。这个指令执行之后,CPU就处于保护模式了。寻址方式也变为保护模式。
这个时候要寻址下一条指令以及数据。寻址时就需要参考影子寄存器中的基地址。而这时候的基地址就是此时的seg << 4。外加偏移。
当然就可以寻址下一条指令以及数据了。在重新装载CS的时候才会根据CS指定的GDT项的内容来重新装载影子寄存器。
貌似intel文档上只说了保护模式下的影子寄存器的作用。 我想在实模式下肯定也用到了... 不然每次都需要seg << 4 + off. 这不是额外的开销么? |
|