(第三章 6)保护模式下,读写大地址内存 & 从32位保护模式跳回16位实模式(二)

三、关于保护模式和实模式的跳转和段描述符高速缓冲寄存器(转载)

     其实从实模式跳转到保护模式还是很好懂得,主要注意就是跳转指令

jmp dword SelectorCode32:0  
//而不能是  
jmp SelectorCode32:0  

     因为这时编译出来的是16位代码。如果目标地址的偏移不是0,而是一个较大的值,比如

jmp SelectorCode32:0x12345678  

     则编译后偏移会被截断,只剩下0x5678。

     所以,这个特殊的跳转需要特殊的处理。在Linux内核中(Linux使用的是AT&T汇编,不是一般常见的IBMPC汇编),这个跳转是用DB指令直接写二进制代码的方法实现的,而NASM显然提供了更好的解决方法,就是加一dword,本来dword应该加在偏移之前,但NASM允许加在整个地址之前,就像我们之前做的那样,这也是NASM的优点吧。

     总之,一个程序中可以包含多个不同位的段,32位或者16位,他们之间也可以互相跳转,只是32位段用的是32位寄存器,16位代码段用的是16位寄存器,如果要在16位段下使用32位寄存器,必须象高级语言中强制类型转换一样,显式的定义 dword。

     而从保护模式跳转回实模式则不是那么好理解了,因为在准备结束保护模式,回到实模式之前,需要加载一个合适的描述符选择子到有关的段寄存器,以使对应段描述符高速缓冲寄存器 (见后面的解释)中含有合适的段界限和属性(这里正确的段界限显然是64K,即0ffffh,属性应该是DA_DRW,即92h在内存中存在的可读写/数据段),而且,不能从32位代码段返回实模式,只能从16位代码段中返回。这是因为无法实现从32位代码段返回时cs高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)

**********************************************************************************************************************************

DA_DRW——在内存中存在的可读写代码段/数据段

 

DA_DRW      EQU 92h ; 存在的可读写数据段属性值 

    92h=0000,0000,1001,0010,也就是将

     TYPE设置为0010,表示可读写。见P36

     S设置为1,表示是数据段/代码段描述符(如果S=0,表示是系统段/门描述符)。见P36

     P设置为1,表示在内存中存在。见P35

**********************************************************************************************************************************

     在实模式下,段寄存器含有段值,为访问存储器形成物理地址时,处理器引用相应的某个段寄存器并将其值乘以16,形成20位的段基地址。在保护模式下,段寄 存器含有段选择子,如上所述,为了访问存储器形成线性地址时,处理器要使用选择子所指定的描述符中的基地址等信息。为了避免在每次存储器访问时,都要访问描述符表而获得对应的段描述符,从80286开始每个段寄存器都配有一个高速缓冲寄存器,称之为段描述符高速缓冲寄存器描述符投影寄存器,对程序员而言它是不可见的。每当把一个选择子装入到某个段寄存器时,处理器自动从描述符表中取出相应的描述符,把描述符中的信息保存到对应的高速缓冲寄存器中。此后访问该段时,处理器都使用对应高速缓冲寄存器中的描述符信息,而不用再从描述符表中取描述符。

     新增的Normal描述符,段界限64K,属性DA_DRW,在返回实模式之前把对应选择子SelectorNormal加载到ds、es和ss正好合适。

猜你喜欢

转载自chuanwang66.iteye.com/blog/1070757