开发学院软件开发汇编语言 汇编教程:控制转移(2) 阅读

汇编教程:控制转移(2)

 2009-02-16 09:36:49 来源:WEB开发网   
核心提示:2.关于实例三的说明有些步骤的实现方法已在前面的实例中做过介绍,下面就任务内无特权级变换的转移和使用局部描述符LDT等作些说明:(1)实模式下初始化LDT演示任务使用了局部描述符表LDT,汇编教程:控制转移(2),本实例中该LDT在实模式下初始化(当然,也可以在使用LDT前的保护模式初始化),无论是否通过调用门,只要不

2.关于实例三的说明
  有些步骤的实现方法已在前面的实例中做过介绍,下面就任务内无特权级变换的转移和使用局部描述符LDT等作些说明:

(1)实模式下初始化LDT
  演示任务使用了局部描述符表LDT,本实例中该LDT在实模式下初始化(当然,也可以在使用LDT前的保护模式初始化)。为了简便,LDT中各描述符的界限和属性值在定义时预置,利用一个子程序设置各段的段基地址。为方便起见,在定义时把各段的段值安排在相应描述符的段基地址低16位字段中。由于实例中各段在实模式下定位(这是因为程序是从实模式下启动执行的),所以把段值乘以16就是对应的段基地址。

(2)装载LDTR寄存器
  在使用LDT之前,还要装载局部描述符表寄存器LDTR。本实例中的如下两条指令用于装载LDTR:

mov  ax,LDT_SEL   lldt  ax 
  LLDT指令是专门用于装载LDTR的指令。该指令的操作数是对应LDT段描述符的选择子。根据该选择子,处理器从GDT中取出相应的LDT段描述符,在进行合法性等检查后,LDT段描述符的基地址和界限等信息被装入LDTR的高速缓冲寄存器中。由于要引用GDT,所以不能在实模式下装载LDTR。在“操作系统类指令”一文中将对LLDT指令作详细说明。

(3)利用段间转移指令JMP实现任务内无特权级的转移
  在本实例中进入保护方式后,特权级是0。通过如下段间直接转移指令实现从代码段K到代码段L的转移:

JUMP16  CodeL_Sel,Virtual2
  其中,选择子CodeL_Sel是对应代码段L的描述符的选择子。该描述符在LDT中,所以选择子中的描述符表指示位TI为1。描述符特权级是0,表示对应代码段的特权级是0,选择子中的请求特权级RPL也是0。目标代码段不是一致代码段,所以在CPL=DPL,RPL<=DPL的情况下,顺利进行相同特权级的转移:目标代码段的选择子CodeL_Sel被装入CS,对应描述符中的信息被装入高速缓冲寄存器中,偏移量Virtual2被装入指令指针寄存器。由于是16位代码段,所以偏移用16位表示。
  类似地,通过如下段间直接转移指令实现从代码段L转移到代码段K:

JUMP16  CodeK_Sel,Virtual3
  其中,选择子CodeK_Sel是对应代码段K的描述符选择子。由于描述符在GDT中,所以选择子中的TI位是0。

(4)利用段间调用指令CALL实现任务内无特权级变换的转移
  在代码段L中,通过段间直接调用指令CALL调用了在代码段C中的两个子程序,这些调用都是无特权级变换的转移。例如,利用如下指令调用了显示字符串子程序DispMsg:

CALL16  CodeC_Sel,DispMsg
  其中,CodeC_Sel是代码段C的选择子,DispMsg表示子程序的入口。描述代码段C的描述符在LDT中,描述符特权级DPL是0,所以使用的选择子CodeC_Sel的请求特权级RPL是0,描述符表指示位TI为1。目标代码段C不是一致代码段,所以在CPL=DPL,RPL<=DPL的情况下,顺利进行相同特权级的转移:当前CS和IP压入堆栈,目标代码段的选择子CodeC_Sel被装入CS,对应描述符中的信息被装入高速缓冲寄存器中,16位偏移DispMsg被装入指令指针IP。由于是16位段,所以偏移用16位表示,压入堆栈的是字而不是双字。

(5)段间返回指令RET实现任务内无特权级变换的转移
  段间返回指令RET从堆栈的栈顶弹出返回地址(由选择子和偏移)构成。弹出选择子内的RPL=CPL,并且对应DPL=CPL,RPL<=DPL是当然的,所以能顺利进行相同特权级的转移。

3.别名技术
  在上述实例三中,使用了两个描述符来描述演示任务的LDT段。段描述符LDTable被安排在GDT中,它是系统段描述符,把段LDTSeg描述成演示任务的局部描述符表LDT。描述符ToLDT被安排在LDT中,它是数据段描述符,把段LDTSeg描述成一个普通数据段。描述符LDTable被装载到LDTR,描述符ToLDT被装载到某个数据段寄存器。为什么要这样处理呢?根据实例三的功能要求,需要访问演示任务的局部描述符表LDT段,以取得代码段L的段界限值,这需要通过某个段寄存器进行,但不能把系统段描述符的选择子装载到段寄存器,所以采用两个描述符来描述段LDTSeg。
  这种为了满足对同一个段实施不同方式操作的需要,而用多个描述符加以描述的技术称为别名技术。在保护方式程序设计中,常常要采用别名技术。例如:用两个具有不同类型值的描述符来描述同一个段。再如,用两个具有不同DPL的描述符来描述同一个段。

<三>任务内不同特权级的变换
  在一个任务内可以存在四种特权级,所以常常会发生不同特权级之间的变换。例如,外层的应用程序调用内层操作系统的例程,以获得必要的诸如存储器分配等系统服务。内层操作系统的例程完成后,返回到外层应用程序。

在同一任务内,实现特权级从外层到内层变换的普通途径是使用段间调用指令CALL,通过调用门进行转移;实现特权级从内层向外层变换的普通途径是使用段间返回指令RET。注意,不能用JMP指令实现任务内不同特权级的变换。

1.通过调用门的转移
  当段间转移指令JMP和段间调用指令CALL所含指针的选择子指示调用门描述符时,就可以实现通过调用门的转移。但只有CALL指令能变换到内层的特权级,JMP指令只能转移到同级的代码。

调用门描述符转移的入口点包含目标地址的段及偏移量的48位全指针。在执行通过任务门的段间转移指令JMP或段间调用指令CALL时,指令所含指针内的选择子用于确定调用门,而偏移被丢弃;把调用门内的48位全指针作为目标地址指针进行转移。

处理器采用与访问数据段相同的特权级规则控制对门描述符的访问。调用门描述符的DPL规定了访问该门的最外层特权级,在取出调用门内的48位全指针,把它作为目标地址指针向目标代码段转移之前,要进行特权级检查。只有在相同级或者更内层特权级的程序才可访问调用门,即CPL<=调用门的DPL。同时,还要求指示门的选择子的RPL必须满足RPL<=调用门的DPL的条件。检测通过后,才开始向目标代码段转移的步骤。其中还要检测目标描述符是否为代码段描述符,调用门内的选择子指示的描述符必须是代码段描述符。此外,在装载代码段描述符高速缓冲寄存器之前调整代码段选择子的RPL=0,也即调用门中代码段选择子的RPL被忽略。


  对于使用调用门的段间转移指令JMP,检测条件与段间直接转移相同。由于已置RPL=0,所以可认为 RPL<=DPL的条件总能满足。所以,对于普通的非一致代码段,当CPL=DPL时,发生无特权级变换的转移;对于一致代码段,在满足CPL>=DPL时也发生无特权级变换的转移;其它情形就引起异常。

对于使用调用门的段间调用指令CALL,情形就不同了。由于已置RPL=0,所以可认为RPL<=DPL的条件总能满足。对于一致代码段,在满足CPL>=DPL时发生无特权级变换的转移。对于非一致代码段,当CPL=DPL时,仍发生无特权级变换的转移;当CPL>DPL时,就发生向内层特权级变换的转移,将调用门中的选择子和偏移装入CS和指令指针EIP中,并使CPL保持等于DPL,同时切换到内层堆栈。

综上所述,使用段间调用指令CALL,通过调用门可以实现从外层程序调用进入内层程序(JMP指令只能实现无特权级变换的转移);通过调用门也可实现无特权级变换的转移。需要注意的是,JMP指令和CALL指令都不能实现向外层特权级的转移否则会引起异常。

当然,CALL指令在最后把目标代码段的指针装入CS和EIP之前,要把原CS和EIP,即返回地址保存到堆栈。如无特权级变换,堆栈保持不变,返回地址就保存在原堆栈中;否则,返回地址保存在内层堆栈中。

2.堆栈切换
  在使用CALL指令通过调用门向内层转移时,不仅特权级发生变换,控制转移到一个新的代码段,而且也切换到内层的堆栈段。从本教程第五篇的任务状态段TSS的格式可见,TSS中包含有指向0级、1级和2级堆栈的指针。在特权级发生向内层变换时,根据变换到的特权级使用TSS中相应的堆栈指针对SS及ESP寄存器进行初始化,建立起一个空栈。

在建立起内层堆栈后,处理器先把外层堆栈的指针SS及ESP寄存器的值压入内层堆栈,以使得相应的向外层返回可恢复原来的外层堆栈。然后,从外层堆栈复制以双字为单位的调用参数到内层堆栈中,调用门中的DCOUNT字段值决定了复制参数的数量。这些被复制的参数是主程序通过堆栈传递给子程序的实参,在调用之前被压入外层堆栈。通过复制栈中的参数,使内层的子程序不需要考虑堆栈的切换,而容易地访问主程序传递过来的实参。最后,调用的返回地址被压入堆栈,以便在调用结束时返回。下图为在向内层变换时,建立内层堆栈,并从外层堆栈复制2个双字参数到内层堆栈的示意图。图中每项是双字,可见的段寄存器内的选择子被扩展成32为存入堆栈,高16位为0。对于16位的使用调用门的段也是如此。

需要注意的是,无论是否通过调用门,只要不发生特权级变换,就不会切换堆栈。

1 2 3 4  下一页

Tags:汇编 教程 控制

编辑录入:爽爽 [复制链接] [打 印]
[]
  • 好
  • 好的评价 如果觉得好,就请您
      0%(0)
  • 差
  • 差的评价 如果觉得差,就请您
      0%(0)
赞助商链接