局部段描述符表的使用

简介: 局部段描述符表的使用

局部段描述符表基本概念

  • 描述符表有 GDT 和 LDT 两种,在保护模式的代码实现中我们用的都是 GDT
  • 现在我们就来学习一下 LDT
  • LDT 全称: Local Descripter table
  • 同 GDT 一样,LDT 本质上也是段描述符表,可以看成段描述符数组
  • 也是通过选择子的方式来访问局部段描述符表中的元素
  • 局部段描述符和选择子与全局段描述符和选择子格式一致

LDT 与 GDT 使用的差异

  • 局部段描述符表从第 0 项开始使用,而全局段描述符表是从第 1 项开始使用
  • 加载局部段描述符表使用的是 lldt 指令,而加载全局段描述符表使用的是 lgdt 指令
  • 局部段描述符表需要在全局段描述符表中注册(增加描述项)

LDT 的意义

  • 它是 CPU 厂商为在硬件一级原生支持多任务而创造的表,按照 CPU 的设想,一个任务对应一个 LDT
  • CPU 厂商建议每个任务的私有内存段都应该放到自己的段描述符表中,该表就是 LDT
  • LDT 是实现多任务的基本要素
  • 当然,现在可能很难理解 LDT 对多任务的意义,可以暂时先放着,心中有个概念就行,后面再逐步具体体会

LDT 的定义与使用

  • 先上完整代码:loader.asm
  • 参考 GDT 的实现,LDT 实现与 GDT 非常相似
  • 首先是局部段描述符表和局部段选择符的定义
; Task A 局部段描述符表定义,段基址先默认为 0 ,后面填充
TASK_A_LDT_BASE     :
TASK_A_CODE32_DESC  : Descriptor 0, TASK_A_CODE32_SEG_LEN - 1,  DA_C + DA_32
TASK_A_DATA32_DESC  : Descriptor 0, TASK_A_DATA32_SEG_LEN - 1,  DA_DR + DA_32
TASK_A_STACK32_DESC : Descriptor 0, TASK_A_STACK32_SEG_LEN - 1, DA_DRW + DA_32
; ...
TASK_A_LDT_LEN      equ   $ - TASK_A_LDT_BASE  ; 长度 = 当前地址 - TASK_A_LDT_BASE 地址
; Task A 局部段选择符定义,RPL = 0; TI = 1
TASK_A_CODE32_SELECTOR    equ   (0x0000 << 3) + SA_RPL0 + SA_TIL
TASK_A_DATA32_SELECTOR    equ   (0x0001 << 3) + SA_RPL0 + SA_TIL
TASK_A_STACK32_SELECTOR   equ   (0x0002 << 3) + SA_RPL0 + SA_TIL
  • 注意 lldt 指令加载的是选择子,与 lgdt 不同
mov ax, TASK_A_LDT_SELECTOR
lldt ax
  • 别忘了段基址需要填充
CODE16_START
  ...
  mov esi, TASK_A_LDT_BASE
  mov edi, TASK_A_LDT_DESC 
  call InitDescItem
  mov esi, TASK_A_CODE32_SEGMENT
  mov edi, TASK_A_CODE32_DESC
  call InitDescItem
  mov esi, TASK_A_DATA32_SEGMENT
  mov edi, TASK_A_DATA32_DESC
  call InitDescItem
  mov esi, TASK_A_STACK32_SEGMENT
  mov edi, TASK_A_STACK32_DESC 
  call InitDescItem
  • 注意,局部段描述符表需要在全局段描述符表中注册(增加描述项),即把局部段描述符表当做一个段,然后给这个段定义一个全局描述符和选择符
; 全局描述符表定义
...
TASK_A_LDT_DESC : Descriptor 0, TASK_A_LDT_LEN-1, DA_LDT
; 全局段选择符定义,RPL = 0; TI = 0
...
TASK_A_LDT_SELECTOR equ (0x0005 << 3) + SA_RPL0 + SA_TIG
  • Task A 的数据段,代码段,栈段实现主体自己查看源码分析。
  • 在原 32 位代码段程序后面添加加载局部段描述符表和跳转到局部代码段执行的代码
mov ax, TASK_A_LDT_SELECTOR
lldt ax
jmp TASK_A_CODE32_SELECTOR:0
  • 于是,程序跳转到 TASK_A_CODE32_SEGMENT 代码处执行
  • TASK_A_CODE32_SEGMENT 处的程序即为局部代码段,实现功能:打印 “Task A” 字符串
  • 注意了:为啥又重新实现了打印函数 TaskAPrintString ,这个函数不是跟 print_str_32 一模一样的吗?
  • 因为 TaskAPrintString 和 print_str_32 不属于同一个代码段,段界限规定了每个程序段的范围,A 程序当然无法调用 B 程序中的代码。这正体现了保护模式的保护二字
  • 最后看一下代码的运行效果

  • 问题:TaskAPrintString 和 print_str_32 实现的功能一模一样,那么,如何实现一个函数,可供不同的代码段调用呢?
  • 请看下一章节讲解
目录
相关文章
【OSTEP】分段(Segmentation) | 地址分段 | 带分段的地址转换
【OSTEP】分段(Segmentation) | 地址分段 | 带分段的地址转换
107 0
|
编译器 C#
C#之十七 局部类型
C#之十七 局部类型
38 0
|
2月前
|
存储
局部对象和全局对象之间的区别是什么
【10月更文挑战第19天】局部对象和全局对象之间的区别是什么
45 2
|
5月前
|
机器学习/深度学习 资源调度 Java
【YOLOv8改进 - 注意力机制】GC Block: 全局上下文块,高效捕获特征图中的全局依赖关系
YOLOv8专栏探讨了目标检测的创新改进,如整合NLNet和SENet优势的GCBlock,用于高效全局上下文建模。GCNet在多个识别任务中表现优越,同时降低了计算成本。文章提供了论文、代码链接及详细实现,包括特征的全局建模、变换和融合步骤。核心GCBlock代码展示了其结构。更多实战案例和配置见相关链接。
|
C语言
分段函数求法(if和switch)
分段函数求法(if和switch)
202 0
西门子S7-1200的运动控制功能、系统使能指令块、错误确认指令块、回参考点或设置参考点指令块的参数含义
今天我们来介绍西门子S7-1200的运动控制功能。西门子S7-1200的运动控制指令是通过使用相关工艺数据块和CPU的专用脉冲串输出来控制轴的运动。
西门子S7-1200的运动控制功能、系统使能指令块、错误确认指令块、回参考点或设置参考点指令块的参数含义
|
C语言
C 中的变量作用域 – 局部和全局作用域解释
C 中的变量作用域 – 局部和全局作用域解释
13:分段函数
13:分段函数
119 0
|
网络协议
网络中解决OSPF不连续区域的3种方法
网络中解决OSPF不连续区域的3种方法
433 0
网络中解决OSPF不连续区域的3种方法
|
存储 关系型数据库 MySQL
段的结构 (4)---独立表空间结构(三十)
段的结构 (4)---独立表空间结构(三十)