6.3.4 Gate Descriptors Guard Procedure Entry Points 门描述符守卫程序入口
To provide protection for control transfers among executable segments at different privilege levels, the 80386 uses gate descriptors. There are four kinds of gate descriptors:
为了在不同特权级别的可执行段中进行控制转移进提供保护,80386使用门描述符。有四种门描述符:
- Call gates 调用门
- Trap gates 陷阱门
- Interrupt gates 中断门
- Task gates 任务门
This chapter is concerned only with call gates. Task gates are used for task switching , and therefore are discussed in . explains how trap gates and interrupt gates are used by exceptions and interrupts. illustrates the format of a call gate. A call gate descriptor may reside in the GDT or in an LDT, but not in the IDT. A call gate has two primary functions:
本章仅涉及调用门。任务门在任务切换时使用,会在第7章讨论。第9章解释在异常和中断时如何使用陷阱门和中断门。图6-5解释了调用门的格式。一个调用门描述符可以入在GDT或LDT中,但不能放在IDT中。调用门有两个基本功能:
- To define an entry point of a procedure. 定义程序入口点
- To specify the privilege level of the entry point. 指定入口点的特权级别
Call gate descriptors are used by call and jump instructions in the same manner as code segment descriptors. When the hardware recognizes that the destination selector refers to a gate descriptor, the operation of the instruction is expanded as determined by the contents of the call gate.
调用门描述符被CALL和JUMP指令以代码段描述符相同的方式使用。当硬件识别出目的选择符引用了一个门描述符时,指令的操作以调用门内容决定的方式被扩展。
The selector and offset fields of a gate form a pointer to the entry point of a procedure. A call gate guarantees that all transitions to another segment go to a valid entry point, rather than possibly into the middle of a procedure (or worse, into the middle of an instruction). The far pointer operand of the control transfer instruction does not point to the segment and offset of the target instruction; rather, the selector part of the pointer selects a gate, and the offset is not used. illustrates this style of addressing.
选择子和门的偏移段构成程序的入口指针。调用门保证向另一个段的转移会有一个有效的入口点,而不是进入程序的中间部分(或者进入一个指令的中间部分)。远程指针操作数不指向段和目标指令的偏移地址;相反,指针的选择子部分选择了一个门,偏移地址不使用。图6-6解释了这种寻址风格。
As shows, four different privilege levels are used to check the validity of a control transfer via a call gate:
正如图6-7所示,四种不同的特权级别被用来检验通过调用门来转移控制的合法性。
- The CPL (current privilege level). 当前特权级CPL
- The RPL (requestor's privilege level) of the selector used to specify the call gate. 选择子的RPL用来指定调用门
- The DPL of the gate descriptor. 门描述符的DPL
- The DPL of the descriptor of the target executable segment.目标可执行段描述符的DPL
The DPL field of the gate descriptor determines what privilege levels can use the gate. One code segment can have several procedures that are intended for use by different privilege levels. For example, an operating system may have some services that are intended to be used by applications, whereas others may be intended only for use by other systems software.
门描述符的DPL决定哪种特权级别可以使用门。一个代码段有多个程序企图被不同特权级别使用。例如,操作系统有许多服务可以被应用程序使用,而其他的仅被系统程序使用。
Gates can be used for control transfers to numerically smaller privilege levels or to the same privilege level (though they are not necessary for transfers to the same level). Only instructions can use gates to transfer to smaller privilege levels. A gate may be used by a instruction only to transfer to an executable segment with the same privilege level or to a conforming segment.
门被用来将控制转移到数值小的特权级别或相同特权级别(尽管在相同级别上转移是不必要的)。仅有CALL指令能使用门来将控制转移到低特权级别。JMP指令使用门时只能向同特权级的代码或一致性段转移控制。
For a instruction to a nonconforming segment, both of the following privilege rules must be satisfied; otherwise, a general protection exception results.
对非一致性段使用JMP指令时,下面特权规则必须被满足;否则会引发一般保护性异常。
MAX (CPL,RPL) <= gate DPL
target segment DPL = CPL
For a instruction (or for a instruction to a conforming segment), both of the following privilege rules must be satisfied; otherwise, a general protection exception results.
对于CALL指令(或对一致性段使用远JMP指令),下面的特权规则必须被满足;否则会引发一般性保护异常。
MAX (CPL,RPL) <= gate DPL
target segment DPL <= CPL
6.3.4.1 Stack Switching 栈切换
If the destination code segment of the call gate is at a different privilege level than the CPL, an interlevel transfer is being requested.
如果调用门的目的代码段处在与CPL不同的特权级别,内部特权转移是必须的。
To maintain system integrity, each privilege level has a separate stack. These stacks assure sufficient stack space to process calls from less privileged levels. Without them, a trusted procedure would not work correctly if the calling procedure did not provide sufficient space on the caller's stack.
为保证系统的健壮,每个特权级别都有独立的栈。这些栈确保充足的栈空间来执行低特权级别的程序调用。否则,如果被调用程序在调用者栈中不能提供充足的空间,被信任的程序将不能正确工作。
The processor locates these stacks via the task state segment (see ). Each task has a separate TSS, thereby permitting tasks to have separate stacks. Systems software is responsible for creating TSSs and placing correct stack pointers in them. The initial stack pointers in the TSS are strictly read-only values. The processor never changes them during the course of execution.
处理器通过任务状态段(见图6-8)来定位这些栈。每个任务都有一个独立的TSS,因此允许任务有独立的栈。系统软件负责创建TSS,并且在其中放置栈指针。TSS中的栈指针初值是只读的。处理器在执行期间决不修改它们。
When a call gate is used to change privilege levels, a new stack is selected by loading a pointer value from the Task State Segment (TSS). The processor uses the DPL of the target code segment (the new CPL) to index the initial stack pointer for PL 0, PL 1, or PL 2.
当调用门被用来修改特权级别,通过从任务状态段(TSS)中载入一个新的指针值来选择一个新栈。处理器使用目标代码段的(新的CPL)DPL来索引一个指向PL0、PL1或PL2初始栈指针。(也就是说,除了特权3以外的每个特权级都有自己的栈,切换到哪个特权级,就使用哪个栈。)
The DPL of the new stack data segment must equal the new CPL; if it does not, a stack exception occurs. It is the responsibility of systems software to create stacks and stack-segment descriptors for all privilege levels that are used. Each stack must contain enough space to hold the old SS:ESP, the return address, and all parameters and local variables that may be required to process a call.
新栈的数据段DPL必须等于新的CPL;如果不等,则发生栈异常。为用到的所有特权级别创建栈和栈段描述符是系统软件的责任。每个栈必须包含足够的空间来保持原SS:ESP、返回地址、所有参数和运行一个调用所需要的本地变量。
As with intralevel calls, parameters for the subroutine are placed on the stack. To make privilege transitions transparent to the called procedure, the processor copies the parameters to the new stack. The count field of a call gate tells the processor how many doublewords (up to 31) to copy from the caller's stack to the new stack. If the count is zero, no parameters are copied.
对于特权级间的调用,子例程的参数被放在栈上。为使用特权转换对于被调用程序透明,处理器拷贝这些参数到新栈。调用门的数量段(count field)告诉处理器需要从调用者栈上拷贝多少双字(最多为31个)到新栈。如果数量为0,没有参数被拷贝。
The processor performs the following stack-related steps in executing an interlevel .
处理器在执行一个特权级间的调用(CALL)时会执行下列与栈相关的步骤。
- The new stack is checked to assure that it is large enough to hold the parameters and linkages; if it is not, a stack fault occurs with an error code of 0.
检验新栈以确保空间足够以放下参数和链接;如果不能,引发一个错误代码为0的栈错误。
- The old value of the stack registers SS:ESP is pushed onto the new stack as two doublewords.
栈寄存器SS:ESP的旧值作为双字被压入到新栈中。
- The parameters are copied.
拷贝参数。
- A pointer to the instruction after the instruction (the former value of CS:EIP) is pushed onto the new stack. The final value of SS:ESP points to this return pointer on the new stack.
CALL指令后面的指令指针(格式为CS:EIP)被压入到新栈中。最后的SS:ESP值,即指向这个返回点的指针也被压入新栈。
illustrates the stack contents after a successful interlevel call.
图6-9解释了段间调用成功手的栈内容。
The TSS does not have a stack pointer for a privilege level 3 stack, because privilege level 3 cannot be called by any procedure at any other privilege level.
TSS没有栈指针指向特权级3的栈,因为特权级3不能被其他任何特权级的程序调用。
Procedures that may be called from another privilege level and that require more than the 31 doublewords for parameters must use the saved SS:ESP link to access all parameters beyond the last doubleword copied.
程序可以被其他特权级调用,这就需要超过31个双字的参数,这就必须使用保存的SS:ESP连接来访问所有参数,越过最后一个被拷贝的双字。
A call via a call gate does not check the values of the words copied onto the new stack. The called procedure should check each parameter for validity. A later section discusses how the , , , , and instructions can be used to check pointer values.
通过调用门的调用(CALL)不再检查拷贝到新栈的字的值。调用程序应当检查每个参数以保证有效。后面部分讨论如何使用ARPL、VERR、VERW、LSL和LAR指令来检查指针值。
6.3.4.2 Returning from a Procedure 从程序返回
The "near" forms of the instruction transfer control within the current code segment and therefore are subject only to limit checking. The offset of the instruction following the corresponding , is popped from the stack. The processor ensures that this offset does not exceed the limit of the current executable segment.
近返回指令(RET)在当前代码段内转移控制,因此只需要进行限长检验。对应的CALL的下一条指令偏移被从栈内弹出。处理器确保这个偏移不超出当前可执行段的限长。
The "far" form of the instruction pops the return pointer that was pushed onto the stack by a prior far instruction. Under normal conditions, the return pointer is valid, because of its relation to the prior or . Nevertheless, the processor performs privilege checking because of the possibility that the current procedure altered the pointer or failed to properly maintain the stack. The RPL of the CS selector popped off the stack by the return instruction identifies the privilege level of the calling procedure.
远返回指令(RET)弹出被远调用CALL指令压入栈内的返回指针。一般情况下,返回点是有效的,因为它与前面的CALL或INT相关联。尽管如此,处理器要对特权级别进行检验,因为有可能当前程序更改了指印或者没有正确的保持栈。返回指令弹出的CS,其选择子的RPL标识了调用程序的特权级别。
An intersegment return instruction can change privilege levels, but only toward procedures of lesser privilege. When the instruction encounters a saved CS value whose RPL is numerically greater than the CPL, an interlevel return occurs. Such a return follows these steps:
段间返回指令可以修改特权级别,但仅限于前方的程序拥有低特权。当返回指令(RET)遇到保存的CS值,其RPL数值大于CPL时,特权级之间的返回发生。下面列出了这种返回的步骤:
- The checks shown in Table 6-3 are made, and CS:EIP and SS:ESP are loaded with their former values that were saved on the stack.
表6-3中所列检查,使用保存在栈上的值来装入CS:EIP和SS:ESP。
- The old SS:ESP (from the top of the current stack) value is adjusted by the number of bytes indicated in the instruction. The resulting ESP value is not compared to the limit of the stack segment. If ESP is beyond the limit, that fact is not recognized until the next stack operation. (The SS:ESP value of the returning procedure is not preserved; normally, this value is the same as that contained in the TSS.)
原SS:ESP值(来自当前栈顶)使用RET指令中的字节数来调整。调整后的ESP值不再与栈段的限长比较。如果ESP超出限长,在下次操作栈之前不能被识别。(返回程序的SS:ESP值不再被保存;通常这个值与保存在TSS中的相同。)
- The contents of the DS, ES, FS, and GS segment registers are checked. If any of these registers refer to segments whose DPL is greater than the new CPL (excluding conforming code segments), the segment register is loaded with the null selector (INDEX = 0, TI = 0). The instruction itself does not signal exceptions in these cases; however, any subsequent memory reference that attempts to use a segment register that contains the null selector will cause a general protection exception. This prevents less privileged code from accessing more privileged segments using selectors left in the segment registers by the more privileged procedure.
DS、ES、FS和GS段寄存器中的内容被检验。如果这些寄存器中任何一个引用 的段,其DPL大于新的CPL(不包括一致性代码段),这个段寄存器会被装入一个空(null)选择子(Index = 0, TI = 0)。返回指令(RET)本身在这种情况下不能发送异常信号;然而,接下来任何使用段寄存器来进行的内存引用,由于其中包含的是一个空选择子,将会引发一个一般性保护异常。这将阻止低特权级代码通过高级特权程序留在寄存器中的选择子来访问高特权级的段。