欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

特权级和调用门

发布时间:2025/6/15 编程问答 35 豆豆
生活随笔 收集整理的这篇文章主要介绍了 特权级和调用门 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

在IA32的分段机制中,总共有4个特权级别,从高到低分别是0、1、2、3。处理器通过识别下面3中特权级进行特权级检验

1.CPL(Current Privilege Level)CPL是当前执行的程序或者任务的特权级,它被存储在CS和SS的第0位和第1位上,通常情况下,CPL等于代码所在的段的特权级,但是有一个例外是如果在遇到一致代码段时,当处理器访问一个与CPL特权级不同的代码段时,CPL不会发生改变。

什么是一致码段呢?它其实是由段描述符数据结构中的属性字段决定的,“一致”的意思是当转移的目标是一个特权级更高的代码段时,当前的特权级会被延续下去,而向特权级更高的非一致代码段转移会引起常规保护错误,除非使用调用们或者任务门。而当目标代码段的特权级低的话,无论它是不是一致代码段,都不能通过call或者jmp转移进去。另外所以的数据段都是非一致的,这意味着不可能被低特权级的代码访问到,然而,与代码段不同的是,数据段可以被更高特权级的代码段访问,而不需要特定的门。

2.DPL(Descriptor Privilege Level) DPL表示段或者门的特权级,它被存储在段描述符或者门描述符的DPL字段中,当当前代码段试图访问一个段或者门时,DPL将会和CPL以及段或者门选择自的RPL相比较。DPL的比较分下面5种情况:

  • 数据段:DPL规定了可以访问此段的最低特权级
  • 非一致代码段(不使用调用门情况下):DPL规定了访问此段的特权级
  • 调用门:DPL规定了当前执行的程序或者任务可以访问此调用门的最低特权级(这个和数据段的规则是一致的)
  • 一致代码段和通过调用门访问的非一致代码段:DPL规定了可以访问此段的最高特权级
  • TSS:DPL规定了可以访问此TSS的最低特权级

3.RPL(Requested Privilege Level) RPL是通过段选择子的第0位和第1位表示出来的。处理器通过检查RPL和CPL来确认一个访问请求是否合法。

所以对数据段的访问比较简单,就是检验特权级,只要CPL和RPL都小于被访问的数据段的DPL就可以了

对程序段的访问比较复杂,程序从一个代码转移到另外一个代码之前,目标代码段的选择子会被加载到cs中,作为加载的一部分,处理器将检查描述符的界限、类型、特权级的内容。如果检验成功,cs将会被加载。

使用jmp或者call指令可以实现下列4种转移:

  • 目标操作数包含目标代码段的段选择子(直接转移)
  • 目标操作数指向一个包含目标代码段选择子的调用门描述符(间接转移)
  • 目标操作数指向一个包含目标代码段选择子的TSS(间接转移)
  • 目标操作数指向一个任务门,这个任务门指向一个包含目标代码段选择子的TSS(间接转移)

调用门:什么是调用门,它也是一种描述符,它的结构定义如下:

; 门

; usage: Gate Selector, Offset, DCount, Attr

;        Selector:  dw

;        Offset:    dd

;        DCount:    db

;        Attr:      db

%macro Gate 4

dw (%2 & 0FFFFh); 偏移 1(2 字节)

dw %1; 选择子(2 字节)

dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性(2 字节)

dw ((%2 >> 16) & 0FFFFh); 偏移 2(2 字节)

%endmacro ; 共 8 字节

和段描述符的6个字节结构不一样,门是由8字节构成,这个描述符也是放置在GDT,LDT或者IDT中以供调用。门描述符分为4种:

  • 调用门
  • 中断门
  • 陷阱门
  • 任务门

门调用其实就是提供了一个入口地址,它可以实现的是不同特权级的代码之间的转移。下面介绍一下具体的过程:

假设我们想由代码A转移到代码B,运用一个调用门G,即调用门G中的目标选择子指向代码B的段,我们涉及这么几个要素:CPL、RPL、代码B的DPL(DPL_B)和调用门的DPL(DPL_G)。根据门调用的规则,A要调用G,则A的CPL和RPL要小于DPL_G,另外还要比较CPL和DPL_B,如果是一致代码段的话,要求DPL_B小于等于CPL,如果是非一致代码段的话,call指令要求DPL_B小于等于CPL,jmp指令要求DPL_B=CPL。

这里我不是特别清楚,可能是如果没有通过门调用,会直接比较RPL和DPL_B,因此门调用能够实现从低特权级到高特权级的转移。

TSS介绍:在进行call和jmp时候,必然要使用堆栈,然而由于不同的特权级会使用不同的堆栈,因此一个任务最多可能有4个堆栈,那么当转移指令在不同特权级之间变化的时候,压入堆栈的内容在另外一个特权级里面已经不是原来的堆栈了,对于这个问题,就引出了TSS(Task-State Stack)这个数据结构。这个数据结构中存在着ss2、esp2;ss1、esp1;ss0、esp0,转移过程如下:

  • 根据目标代码的DPL从TSS中选择应该切换至哪个ss和esp
  • 从TSS中读取新的ss和esp
  • 暂时性地保存当前的ss和esp的值
  • 加载新的ss和esp
  • 将刚刚保存起来的ss和esp的值压入新栈
  • 将当前的cs和eip压栈
  • 加载调用门中指定的新的cs和eip。
  • 所以,从上面的过程中我们可以知道,在进行特权级转移时,首先根据目标代码的DPL从TSS中取得对应的ss和esp,然后加载新的ss和esp,也就是使用新的堆栈,并把老的堆栈的信息压入新栈,以便返回时使用,然后再进行转移

     

     

     

    下面说明代码段和数据段的访问:


    一、代码段间跳转


    1、普通(直接)跳转:

    JMP Selector:0 或 CALL Selector:0

    1)一致代码段(JMP&CALL)

    要求:CPL>=DPL,RPL不作检查

    特权变化:跳转后程序CPL=跳转前程序CPL

    2)非一致代码段(JMP&CALL)

    要求:CPL=DPL & RPL<=DPL

    特权变化:跳转后程序CPL=目标代码段DPL


    2、通过调用门跳转:

    JMP 调用门Selector:0 或 CALL 调用门Selector:0 (注意:此时如果选择子后面跟着32位偏移量也不会被CPU使用,因为调用门描述符已经记录了目标代码的偏移)


    step1: 要求:指示调用门的选择子的RPL<=门描述符DPL & 当前代码段的CPL<=门描述符的DPL。


    只有满足以上条件时,CPU才会进一步从调用门描述符中读取代码段的选择子或地址偏移。而从调用门中读取代码选择子和地址偏移后,跟普通跳转又站在同一起跑线上了。

    唯一不同的是CPU会将目标代码段RPL清0。此后需要分类讨论,如下:


    step2:

    1)一致代码段(JMP&CALL)  <------------------------------------------------------------------------------------------------------

    要求:CPL>=DPL,RPL不作检查(因为RPL总被清0)                                                        |

    特权变化:跳转后程序CPL=跳转前程序CPL                                                                        |

                                                                                                                                                 比较

    2)非一致代码段(JMP)                                                                                                                |

    要求:CPL=DPL,RPL不作检查(因为RPL总被清0)                                                          |

    特权变化:跳转后程序CPL=目标代码段DPL                                                                        |

    3)非一致代码段(CALL)  <------------------------------------------------------------------------------------------------------------

    要求:CPL>=DPL,RPL不作检查(因为RPL总被清0)

    特权变化:跳转后程序CPL=目标代码段DPL(CPL>DPL的情况下,特权级发生跃迁)


    二、访问数据段

    数据段:特权级低->高:NO | 特权级高->低:YES | 特权级同级之间:YES


    注意:

    1、一致代码段:无论那种方式跳转到一致代码段,CPL都不会改变(不变化为目标代码段的DPL),也即加载目标代码段选择子时,只加载高14位,表示CPL的低2位保持不变。

    因此,“一致”的意思就是——代码段被调用执行时,不使用自己描述符的DPL,而采用调用这特权级,CS的低2位保持不变(与“调用者保持一致”)

    2、非一致代码段:无论采用哪种方式跳转到非一致代码段,CPL都发生变化,也即在加载目标代码段选择子时,将整个选择子放入到CS中。

    3、为了访问调用门,调用者程序的特权级CPL必须小于或等于调用门的DPL。调用门段选择符的RPL也要同调用CPL一样遵守相同的规则,即RPL也必须小于或等于调用门的DPL

    总结

    以上是生活随笔为你收集整理的特权级和调用门的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。