调用门

简介: 调用门

引言

  • 【局部段描述符表的使用】 的最后,我们留下了一个问题,为了解决这个问题,于是引出了调用门
  • 当然,关于实现不同代码段之间的代码复用功能(调用同一个函数),不光只有调用门这一种方案
  • 这里讲调用门不光是因为其可以实现不同代码段之间的代码复用,而且其能在不同特权级的代码段之间跳转执行。关于特权级跳转,下一章节再详细说明
  • 在这一章节,我们只需要认识调用门,不要过多的深入到其它地方

门描述符

  • 前面章节我们学习了多种段描述符,今天我们来学习一种新的描述符:门描述符
  • 根据应用场景的不同,门描述符可分为
  • 调用门
  • 中断门
  • 陷阱门
  • 任务门

调用门描述符格式

  • 门描述符同段描述符类似,都是 8 字节大小的数据结构,现在,我们只看调用门描述符格式

  • 调用门中的段选择符字段指定要访问的代码段
  • 偏移值字段指定段中入口点。这个入口点通常是指定过程的第一条指令
  • DPL 字段指定调用门的特权级,从而指定通过调用门访问特定过程所要求的特权级
  • 标志 P 指明调用门描述符是否有效
  • 参数个数字段(Param Count)指明在发生堆栈切换时从调用者堆栈复 制到新堆栈中的参数个数

调用门执行过程

  • 调用门执行过程:当处理器访问调用门时,它会使用调用门中的段选择符来定位目的代码段的段描述符。然后 CPU 会把代码段描述符的基地址与调用门中的偏移值进行组合,形成代码段中指定程序入口点的线性地址。

代码实现

  • 接下来我们使用调用门来实现不同代码段之间打印函数复用功能
  • 先上完整代码:loader.asm
  • 参照段描述符宏定义的方式,给门描述符也做个宏定义
; 门描述符定义
%macro Gate 4               ; 有四个参数:选择子、偏移地址、参数个数、属性
    dw    (%2 & 0xFFFF)                      ; 偏移地址1
    dw    %1                                 ; 选择子
    dw    (%3 & 0x1F) | ((%4 << 8) & 0xFF00) ; 属性
    dw    ((%2 >> 16) & 0xFFFF)              ; 偏移地址2
%endmacro
  • 首先我们把打印函数单独放在一个专门的代码段中,注意,不同段之间的函数返回必须用 retf ,不能用 ret
FUNCTION_SEGMENT:
print_str_32:
  ...
  函数主体
  ...
  retf
printOffset equ print_str_32 - FUNCTION_SEGMENT
FUNC_SEG_LEN equ $-FUNCTION_SEGMENT
  • 那么对应的就要有一个段描述符和选择符
; 段描述符
FUNC_DESC : Descriptor 0, FUNC_SEG_LEN-1, DA_C + DA_32
; 段选择符
FUNC_SELECTOR equ (0x0006 << 3) + SA_RPL0 + SA_TIG

; 段选择符

FUNC_SELECTOR equ (0x0006 << 3) + SA_RPL0 + SA_TIG

  • 填充段基址

mov esi, FUNCTION_SEGMENT

mov edi, FUNC_DESC

call InitDescItem

  • 以上操作与之前完全相同
  • 接下来还需要定义门描述符和对应的选择符
; 门描述符
FUNC_PRINT_DESC : Gate FUNC_SELECTOR, printOffset, 0, DA_CALL_GATE  
; 选择符
FUNC_PRINT_SELECTOR equ (0x0007 << 3) + SA_RPL0 + SA_TIG
  • 最后,函数调用也变为:
; call print_str_32
call FUNC_PRINT_SELECTOR : 0
; call TaskAPrintString
call FUNC_PRINT_SELECTOR : 0
  • 也可以不使用调用门实现不同代码段的函数复用,其格式为:call 选择子 : 偏移地址
; call print_str_32
; call FUNC_PRINT_SELECTOR : 0
call FUNC_SELECTOR : printOffset
; call TaskAPrintString
; call FUNC_PRINT_SELECTOR : 0
call FUNC_SELECTOR : printOffset
  • 运行一下,打印信息跟上一章节一模一样
目录
相关文章
|
机器学习/深度学习 算法 机器人
使用 Python TorchRL 进行多代理强化学习
本文详细介绍了如何使用TorchRL库解决多代理强化学习(MARL)问题,重点讨论了在多代理环境中应用近端策略优化(PPO)。通过使用VMAS模拟器,该文展示了如何在GPU上并行训练多机器人系统,使其在避免碰撞的同时到达目标。文章涵盖了依赖项安装、PPO原理、策略与评论家网络设计、数据收集及训练循环,并强调了TorchRL在简化开发流程、提升计算效率方面的优势。无论是集中式还是分布式评论家配置,TorchRL均能有效支持复杂的MARL研究与实践。
189 5
使用 Python TorchRL 进行多代理强化学习
|
运维 架构师
架构师“三部曲”——阿里云 MVP 沈剑
沈剑,公众号“架构师之路”的作者,曾任百度高级工程师和58同城高级架构师、技术委员会主席、技术学院优秀讲师,现为到家集团技术委员会主席和技术VP,同时也是快狗打车(原58速运)的CTO。本文是沈剑老师在阿里云的直播中分享的一些自己关于架构师的看法和成为架构师的心路历程的第二部分。
3796 0
架构师“三部曲”——阿里云 MVP 沈剑
|
Ubuntu
Ubuntu :relocation R_X86_64_32 against `.rodata‘ can not be used when making a PIE object;
Ubuntu :relocation R_X86_64_32 against `.rodata‘ can not be used when making a PIE object;
3297 0
Ubuntu :relocation R_X86_64_32 against `.rodata‘ can not be used when making a PIE object;
|
10月前
|
存储 NoSQL Redis
Redis 为什么这么快?4 大核心设计图解!
本文详细解析了 Redis 的高性能设计,包括内存存储、单线程模型、IO多路复用技术和数据结构优化,帮助更好地理解和应用 Redis。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Redis 为什么这么快?4 大核心设计图解!
|
10月前
|
机器学习/深度学习 人工智能 自然语言处理
Tokenformer:基于参数标记化的高效可扩展Transformer架构
本文是对发表于arXiv的论文 "TOKENFORMER: RETHINKING TRANSFORMER SCALING WITH TOKENIZED MODEL PARAMETERS" 的深入解读与扩展分析。主要探讨了一种革新性的Transformer架构设计方案,该方案通过参数标记化实现了模型的高效扩展和计算优化。
531 0
|
C#
WPF技术之Visibility
WPF中的Visibility属性用于控制元素在界面上的可见性。
782 1
|
缓存 JSON 负载均衡
构建高效RESTful API的最佳实践
【4月更文挑战第22天】在当今互联网应用的开发中,后端系统的核心通常体现在API的设计和实现上。一个设计良好、性能优异的RESTful API能够极大地提升应用的响应速度及用户体验。本文将探讨在构建高效RESTful API时应当遵循的一系列最佳实践,包括合理的数据结构设计、缓存策略、负载均衡技术以及API版本管理等。通过这些实践,可以确保API服务的高性能与易维护性,并适应不断变化的业务需求。
|
SQL 数据可视化 数据挖掘
Hive窗口函数详细介绍
Hive窗口函数详细介绍
390 0
|
存储
数据交换技术
数据交换技术。
433 2