通过调用门进行控制转移

1. 关于堆栈切换

如果通过调用门把控制转移到了更高特权级的非一致代码段中,那么CPL就会被设置为目标代码段的DPL值,并且会引起堆栈切换。为什么要切换堆栈呢?原因有以下几点:
1. 因为栈段的特权级必须同CPL保持一致;
2. 防止高特权级程序由于栈空间不足而崩溃;
3. 防止低特权级程序通过共享的栈有意或无意地干扰高特权级程序。

为了切换栈,每个任务除了自己的固有栈之外,还必须额外定义一套或多套栈,具体是多少取决于任务的特权级别。
0特权级的任务不需要额外的栈,因为除了从调用高特权级的例程(通常是操作系统例程)返回外,不允许将控制从特权级高的代码段转移到特权级低的代码段——操作系统不会引用可靠性比自己低的代码;1特权级的任务需要额外定义一个DPL为0的栈,以便将控制转移到0特权级时使用;2特权级的任务需要额外定义两个栈,其DPL分别为0和1;3特权级的任务最多额外定义三个栈,其DPL分别为0、1、2.

以下文字摘自《Intel Architecture Software Developer’s Manual Volume 3:System Programming》的4.8.5节——Stack Switching.

Each task must define up to 4 stacks: one for applications code (running at privilege level 3) and one for each of the privilege levels 2, 1, and 0 that are used. (If only two privilege levels are used[3 and 0], then only two stacks must be defined.)

操作系统负责为任务用到的所有特权级分配栈空间和创建栈段描述符,并且在任务的TSS中填写栈段的选择子和ESP的初始值(下图是TSS的一部分)。

有几点需要注意:
1. 每个栈必须可读可写,并且具有足够的空间来存放以下信息:
(1)调用过程的SS、ESP、CS和EIP寄存器的内容
(2)被调用过程的参数和临时变量所需使用的空间
(3)当隐含调用一个异常或者中断过程时标志寄存器EFLAGS和出错码使用的空间
2. 由于一个过程可以调用其他过程,因此每个栈必须有足够的空间来容纳多帧信息
3. TSS中的中的SSx、ESPx(x=0,1,2)字段是静态的,除非软件进行修改,处理器从来不会改变它们。举例来说,假设操作系统为一个用户任务的TSS填写了ESP0,其值为0x800;当这个任务通过调用门进入0特权级的代码段时,会切换到0特权级堆栈,堆栈指针ESP的初始值就是0x800;返回时,假设ESP变成了0x808,处理器并不会把0x808更新到TSS中的ESP0域;下次再通过调用门进入0特权级代码段时,使用的还是当初设置的静态值0x800。

2. 通过调用门进行控制转移和返回的具体过程

2.1 转移的过程

首先,通过调用门进行控制转移,可以使用jmp far或者call far指令。指令执行时,段选择子必须指向调用门,32偏移量可以是任意值(会被CPU忽略)。

其次,必须符合下表的特权级检查规则。

再次,当使用call far指令通过调用门转移控制时,如果改变了CPL,则必须切换栈,即从当前任务的固有栈切换到与目标代码段特权级相同的栈上。栈的切换是由处理器固件自动进行的。

当前栈是由SS和ESP的当前内容所指示的。要切换到的新栈的相关信息位于当前任务的TSS中,处理器知道如何找到它。栈切换过程如下:
1. 根据目标代码段的DPL(也就是新的CPL)到当前任务的TSS中读取新栈的选择子和栈指针。在读取栈选择子、栈指针或者栈段描述符的过程中,任何违反段界限的错误都将导致产生一个无效TSS异常。
2. 检查栈段描述符的特权级和类型是否有效,若无效同样产生一个无效TSS异常。
3. 临时保存SS和ESP的当前值,把新栈的选择子和栈指针加载到SS和ESP中。然后把临时保存的SS和ESP的内容压入新栈中。
4. 根据调用门描述符中“参数个数”字段,把旧栈中的所有参数复制到新栈中。如果参数个数为0,则不复制参数。
5. 将当前CS和EIP的内容压入新栈。通过调用门实施的控制转移一定是远转移,所以要压入CS和EIP。
6. 从调用门描述符中把目标代码段的选择子和段内偏移值传送到CS和EIP中,开始执行被调用过程。

相反,如果没有改变特权级别,则不切换栈,继续使用调用者当前的栈,只是在原来的基础上压入当前CS和EIP的内容。

另外,如果通过调用门的控制转移是jmp far指令发起的,结果就是“肉包子打狗——有去无回”,且没有特权级变化,也不需要切换栈。相反,如果是call far指令发起的,则可以使用远返回指令retf把控制返回到调用者。

2.2. 返回的过程

对于相同特权级的返回,CPU从堆栈中弹出EIP和CS;会发生特权级改变的远返回仅允许返回到低特权级程序中,即返回到的代码段的DPL在数值上要大于CPL。返回的全部过程如下:

  1. 检测被调用者栈中CS寄存器的RPL字段值,以确定在返回时特权级是否发生改变。
  2. 弹出并使用被调用过程栈上的值加载EIP和CS寄存器。在此过程中会对代码段描述符和代码段选择子的RPL进行特权级与类型检查。
  3. 如果远返回指令是带参数的,则将参数和ESP寄存器的当前值相加,以跳过被调用者栈中的参数部分,最后的结果是ESP寄存器指向调用者SS和ESP的压栈值。注意,retf指令的参数必须等于调用门中所有参数的总字节数之和。
  4. 如果返回时需要改变特权级,则从栈中将ESP和SS弹出,并把值代入寄存器ESP和SS,切换到调用者的栈。
  5. 如果远返回指令是带参数的,则将参数和ESP寄存器的当前值相加,以跳过调用者栈中的参数部分,最后的结果是调用者的栈恢复平衡。
  6. 如果返回时需要改变特权级,则检查DS,ES,FS和GS的内容,如果段选择子指向数据段或者非一致代码段且段描述符的DPL在数值上小于返回后的新CPL,那么就把数值0传送到该段寄存器。

通过调用门进行控制转移 ——《x86汇编语言:从实模式到保护模式》读书笔记29相关推荐

  1. 代码段间转移控制时的特权级检查(JMP/CALL)——《x86汇编语言:从实模式到保护模式》读书笔记28

    代码段间转移控制时的特权级检查(JMP或者CALL指令) 在保护模式下,JMP或CALL指令可以用以下四种方法之一来引用另外一个代码段: 1. 目标操作数含有目标代码段的段选择子和偏移 2. 目标操作 ...

  2. [书]x86汇编语言:从实模式到保护模式 -- 第14章 任务和特权级保护,调用门、LDT、TSS、TCB

    # 加载用户程序 Part 1.TCB, Task Control Block, 任务控制块 分配内存作为该任务的TCB,并插入至TCB链表. Part 2.LDT, Locak Descriptor ...

  3. X86汇编语言从实模式到保护模式16:特权级和特权级保护

    目录 1. 特权级保护机制 1.1 基础段保护机制的不足 1.2 特权级划分 1.3 特权级的表示 1.3.1 当前特权级CPL 1.3.2 描述符特权级DPL 1.3.3 请求特权级RPL 1.4 ...

  4. 任务和特权级保护(二)——《x86汇编语言:从实模式到保护模式》读书笔记32

    之前做了那么多铺垫,我们终于可以看看第14章的代码了. 对于引导代码和用户程序,依然采用第13章的:对于内核程序(c14_core.asm),编译的时候有几行报错了,只要加上dword即可解决. 1. ...

  5. [书]x86汇编语言:从实模式到保护模式 -- 第17章 中断、任务切换、分页机制、平坦模型

    # 任务切换 内核任务.用户任务1.用户任务2,之前的轮询切换 利用RTC芯片的硬件中断来实现任务切换 计算机主板上有实时时钟芯片RTC,可以设置RTC芯片,使得它每次更新CMOS中的时间信息后,发出 ...

  6. [书]x86汇编语言:从实模式到保护模式 -- 第16章 分页机制、平坦模型

    # 分页机制 二级页表:页目录.页表 ==> 4KB物理页 32位线性地址中:高10位为页目录中的索引号(乘4得偏移量),该目录项指向页表的基地址:中间10位为页表中的索引号,该页表项指向4KB ...

  7. [书]x86汇编语言:从实模式到保护模式 -- 第15章 任务切换

    # 执行结果 # TODO:字符串显示函数的滚屏部分应该是有bug. # file_02: c15_core.asm ; FILE: c13_core.asm ; DATE: 20200104 ; T ...

  8. 硬盘和显卡的访问与控制(一)——《x86汇编语言:从实模式到保护模式》读书笔记01

    本文是<x86汇编语言:从实模式到保护模式>(电子工业出版社)的读书实验笔记. 这篇文章我们先不分析代码,而是说一下在Bochs环境下如何看到实验结果. 需要的源码文件 第一个文件是加载程 ...

  9. 任务切换——《x86汇编语言:从实模式到保护模式》读书笔记38

    任务切换--<x86汇编语言:从实模式到保护模式>读书笔记38 本文及后面的几篇博文是原书第15章的学习笔记. 本章依然使用第13章的主引导程序. 1. 协同式多任务与抢占式多任务 有两种 ...

最新文章

  1. jcDate时间选取jQuery插件
  2. 北京理工大学计算机学院赵曜,北理工学子参加第十届蓝桥杯全国软件和专业人才大赛取得佳绩...
  3. 调试maven源代码
  4. 30hibernate_fetch_1_select
  5. 基于Python-turtle库绘制哆啦A梦
  6. linux下进程号,Linux下C++获取进程号
  7. windows idea Tomcat端口被占用
  8. 存档修改 html,制作可以修改.rpgsave存档的网页
  9. 传智播客python高级-2018年传智播客黑马python15期
  10. CCSK安全认证-M1-云计算概念和体系架构
  11. 裁员浪潮,互联网人该何去何从?
  12. ArcGIS读取天地图2.0
  13. 洛谷P4572 [JSOI2013] 哈利波特与死亡圣器
  14. 霍营派出所办理居住证
  15. 华为手机计算机怎么语音算术,华为自带的语音识别功能太实用了!这样操作,3秒语音变文字...
  16. 5G应用创新发展策略研究
  17. 完美国际真数苹果_苹果 or 谷歌,到底谁的设计更好?
  18. 用STM32F407ZET6的HAL库写一个串口接收,发送代码,支持ringbuff
  19. Silverlight框架
  20. mc服务器修改世界边境,[转载插件] [安全]WorldBorder——限制世界边界范围大小【1.0.1 - 1.7.9】...

热门文章

  1. bzoj4665: 小w的喜糖
  2. 腾讯云 wdcp ip:8080打不开,wdcp phpmyadmin打不开
  3. C# WinForm 添加Windows Media Player 控件调试出现未能加载文件或程序集Interop.WMPLib,该怎么解决...
  4. 安装logstash,elasticsearch,kibana三件套
  5. Objective-C知识总结(5)
  6. keras入门之手写字识别python代码
  7. TensorFlow版本
  8. 程序基础:数据结构(郝斌讲解)(2)
  9. 如何在CentOS 5/6上安装EPEL源
  10. 从其它地方复制的代码到VS 提示无法识别的标记的解决办法