局部段描述符表的使用

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

局部段描述符表基本概念

  • 描述符表有 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 实现的功能一模一样,那么,如何实现一个函数,可供不同的代码段调用呢?
  • 请看下一章节讲解
目录
相关文章
|
移动开发 前端开发 API
深入理解前端路由:构建现代 Web 应用的基石(上)
深入理解前端路由:构建现代 Web 应用的基石(上)
深入理解前端路由:构建现代 Web 应用的基石(上)
|
API 数据库 流计算
有大佬知道在使用flink cdc实现数据同步,如何实现如果服务停止了对数据源表的某个数据进行删除操作,重启服务之后目标表能进行对源表删除的数据进行删除吗?
【2月更文挑战第27天】有大佬知道在使用flink cdc实现数据同步,如何实现如果服务停止了对数据源表的某个数据进行删除操作,重启服务之后目标表能进行对源表删除的数据进行删除吗?
228 3
|
Ubuntu
Ubuntu的中文乱码问题
Ubuntu的中文乱码问题
818 2
|
10月前
|
安全 物联网 物联网安全
智能物联网安全:物联网设备的防护策略与最佳实践
【10月更文挑战第27天】随着物联网技术的快速发展,智能设备已广泛应用于生活和工业领域。然而,物联网设备的安全问题日益凸显,主要威胁包括中间人攻击、DDoS攻击和恶意软件植入。本文探讨了物联网设备的安全防护策略和最佳实践,包括设备认证和加密、定期更新、网络隔离以及安全标准的制定与实施,旨在确保设备安全和数据保护。
440 0
|
存储 中间件 数据库连接
|
存储 SQL 关系型数据库
使用关系型数据库三级模式存储数据的优缺点
【6月更文挑战第10天】数据模型是DBMS的核心,提供数据透明性和设计指导。包括概念、逻辑和物理三层:概念模型(如ER模型)用于理解和收集需求,逻辑模型(如关系模型)关注设计,物理模型涉及实际存储实现。
229 0
使用关系型数据库三级模式存储数据的优缺点
|
安全 网络协议
curl使用小记(四)——在多线程中使用的问题总结
curl使用小记(四)——在多线程中使用的问题总结
567 0
|
12月前
|
Go
Golang语言结构体(struct)面向对象编程进阶篇(封装,继承和多态)
这篇文章是关于Go语言中结构体(struct)面向对象编程进阶篇的教程,涵盖了Go语言如何实现封装、继承和多态,以及结构体内存布局的相关概念和案例。
373 4
|
网络协议 Linux 存储
深入理解Linux网络——TCP连接建立过程(三次握手源码详解)
一、相关实际问题 1. 为什么服务端程序都需要先listen一下 2. 半连接队列和全连接队列长度如何确定 3. “Cannot assign requested address”这个报错是怎么回事 4. 一个客户端端口可以同时用在两条连接上吗 5. 服务端半/全连接队列满了会怎么样 6. 新连接的soket内核对象是什么时候建立的 7. 建立一条TCP连接需要消耗多长时间 8. 服务器负载很正常,但是CPU被打到底了时怎么回事
|
Kubernetes API 数据安全/隐私保护
k8s学习-基于角色的权限控制RBAC(概念,模版,创建,删除等)
k8s学习-基于角色的权限控制RBAC(概念,模版,创建,删除等)
393 0