高特权级代码段转向低特权级代码段(利用 ret(retf) 指令实现 jmp from ring0 to ring3)

【0】写在前面

  • 0.1)本代码旨在演示 从 ring0 转移到 ring3(即,从高特权级 转移到 低特权级)
  • 0.2)本文 只对 与 门相关的 代码进行简要注释,言简意赅;
  • 0.3)文末的个人总结是干货,前面代码仅供参考的,且source code from orange’s implemention of a os.

; ==========================================
; pmtest5a.asm
; 编译方法:nasm pmtest5a.asm -o pmtest5a.com
; ==========================================%include    "pm.inc"    ; 常量, 宏, 以及一些说明org 0100hjmp    LABEL_BEGIN

;[SECTION .gdt]

; GDT
;                           段基址,       段界限     , 属性
LABEL_GDT:             Descriptor 0,                0, 0         ; 空描述符
LABEL_DESC_NORMAL:     Descriptor 0,           0ffffh, DA_DRW    ; Normal 描述符
LABEL_DESC_CODE32:     Descriptor 0,   SegCode32Len-1, DA_C+DA_32; 非一致代码段,32
LABEL_DESC_CODE16:     Descriptor 0,           0ffffh, DA_C      ; 非一致代码段,16
LABEL_DESC_CODE_DEST:  Descriptor 0, SegCodeDestLen-1, DA_C+DA_32; 非一致代码段,32

; ring3的代码段描述符的定义 [add]

LABEL_DESC_CODE_RING3: Descriptor 0,SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3
LABEL_DESC_DATA:       Descriptor 0,        DataLen-1, DA_DRW    ; Data
LABEL_DESC_STACK:      Descriptor 0,       TopOfStack, DA_DRWA+DA_32;Stack, 32 位

; ring3的堆栈段描述符的定义 [add]

LABEL_DESC_STACK3:     Descriptor 0,      TopOfStack3, DA_DRWA+DA_32+DA_DPL3
LABEL_DESC_LDT:        Descriptor 0,         LDTLen-1, DA_LDT    ; LDT

; ring3的视频段描述符的DPL属性设置为 3 [add]

LABEL_DESC_VIDEO:      Descriptor 0B8000h,     0ffffh, DA_DRW+DA_DPL3; 门                               目标选择子,偏移,DCount, 属性
LABEL_CALL_GATE_TEST: Gate SelectorCodeDest,   0,     0, DA_386CGate+DA_DPL0
; GDT 结束GdtLen   equ    $ - LABEL_GDT  ; GDT长度
GdtPtr   dw GdtLen - 1  ; GDT界限dd    0    ; GDT基地址; GDT 选择子
SelectorNormal   equ    LABEL_DESC_NORMAL   - LABEL_GDT
SelectorCode32   equ    LABEL_DESC_CODE32   - LABEL_GDT
SelectorCode16   equ    LABEL_DESC_CODE16   - LABEL_GDT
SelectorCodeDest    equ LABEL_DESC_CODE_DEST    - LABEL_GDT

; ring3的代码段描述符的选择子定义 [add]

SelectorCodeRing3   equ LABEL_DESC_CODE_RING3   - LABEL_GDT + SA_RPL3SelectorData     equ    LABEL_DESC_DATA  - LABEL_GDT
SelectorStack    equ    LABEL_DESC_STACK    - LABEL_GDT

; ring3的堆栈段描述符的选择子定义 [add]

SelectorStack3   equ    LABEL_DESC_STACK3   - LABEL_GDT + SA_RPL3SelectorLDT  equ    LABEL_DESC_LDT   - LABEL_GDT

;ring3的视频段描述符(DPL==3)的选择子定义 [add]

SelectorVideo    equ    LABEL_DESC_VIDEO    - LABEL_GDTSelectorCallGateTest    equ LABEL_CALL_GATE_TEST    - LABEL_GDT
; END of [SECTION .gdt]

[SECTION .data1] ; 数据段

ALIGN   32
[BITS   32]
LABEL_DATA:
SPValueInRealMode   dw  0
; 字符串
PMMessage:   db "In Protect Mode now. ^-^", 0   ; 进入保护模式后显示此字符串
OffsetPMMessage  equ    PMMessage - $$StrTest:	 db	"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0OffsetStrTest	 equ	StrTest - $$
DataLen  equ    $ - LABEL_DATA
; END of [SECTION .data1]

; 全局堆栈段
[SECTION .gs]

ALIGN   32
[BITS   32]
LABEL_STACK:times 512 db 0TopOfStack  equ $ - LABEL_STACK - 1; END of [SECTION .gs]

; 堆栈段ring3的定义
[SECTION .s3]

ALIGN   32
[BITS   32]
LABEL_STACK3:times 512 db 0
TopOfStack3 equ $ - LABEL_STACK3 - 1
; END of [SECTION .s3]

[SECTION .s16]

[BITS   16]
LABEL_BEGIN:mov    ax, csmov    ds, axmov    es, axmov    ss, axmov    sp, 0100hmov    [LABEL_GO_BACK_TO_REAL+3], axmov    [SPValueInRealMode], sp; 初始化 16 位代码段描述符mov    ax, csmovzx  eax, axshl    eax, 4add    eax, LABEL_SEG_CODE16mov    word [LABEL_DESC_CODE16 + 2], axshr    eax, 16mov    byte [LABEL_DESC_CODE16 + 4], almov    byte [LABEL_DESC_CODE16 + 7], ah; 初始化 32 位代码段描述符xor    eax, eaxmov    ax, csshl    eax, 4add    eax, LABEL_SEG_CODE32mov    word [LABEL_DESC_CODE32 + 2], axshr    eax, 16mov    byte [LABEL_DESC_CODE32 + 4], almov    byte [LABEL_DESC_CODE32 + 7], ah; 初始化测试调用门的代码段描述符xor    eax, eaxmov    ax, csshl    eax, 4add    eax, LABEL_SEG_CODE_DESTmov    word [LABEL_DESC_CODE_DEST + 2], axshr    eax, 16mov    byte [LABEL_DESC_CODE_DEST + 4], almov    byte [LABEL_DESC_CODE_DEST + 7], ah; 初始化数据段描述符xor    eax, eaxmov    ax, dsshl    eax, 4add    eax, LABEL_DATAmov    word [LABEL_DESC_DATA + 2], axshr    eax, 16mov    byte [LABEL_DESC_DATA + 4], almov    byte [LABEL_DESC_DATA + 7], ah; 初始化堆栈段描述符xor    eax, eaxmov    ax, dsshl    eax, 4add    eax, LABEL_STACKmov    word [LABEL_DESC_STACK + 2], axshr    eax, 16mov    byte [LABEL_DESC_STACK + 4], almov    byte [LABEL_DESC_STACK + 7], ah

; 初始化堆栈段描述符(Ring3) [add]

 xor    eax, eaxmov    ax, dsshl    eax, 4add    eax, LABEL_STACK3mov    word [LABEL_DESC_STACK3 + 2], axshr    eax, 16mov    byte [LABEL_DESC_STACK3 + 4], almov    byte [LABEL_DESC_STACK3 + 7], ah; 初始化 LDT 在 GDT 中的描述符xor    eax, eaxmov    ax, dsshl    eax, 4add    eax, LABEL_LDTmov    word [LABEL_DESC_LDT + 2], axshr    eax, 16mov    byte [LABEL_DESC_LDT + 4], almov    byte [LABEL_DESC_LDT + 7], ah; 初始化 LDT 中的描述符xor    eax, eaxmov    ax, dsshl    eax, 4add    eax, LABEL_CODE_Amov    word [LABEL_LDT_DESC_CODEA + 2], axshr    eax, 16mov    byte [LABEL_LDT_DESC_CODEA + 4], almov    byte [LABEL_LDT_DESC_CODEA + 7], ah

; 初始化Ring3描述符 [add]

 xor    eax, eaxmov    ax, dsshl    eax, 4add    eax, LABEL_CODE_RING3mov    word [LABEL_DESC_CODE_RING3 + 2], axshr    eax, 16mov    byte [LABEL_DESC_CODE_RING3 + 4], almov    byte [LABEL_DESC_CODE_RING3 + 7], ah; 为加载 GDTR 作准备xor    eax, eaxmov    ax, dsshl    eax, 4add    eax, LABEL_GDT   ; eax <- gdt 基地址mov    dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址; 加载 GDTRlgdt   [GdtPtr]; 关中断cli; 打开地址线A20in al, 92hor al, 00000010bout    92h, al; 准备切换到保护模式mov    eax, cr0or eax, 1mov    cr0, eax; 真正进入保护模式jmp    dword SelectorCode32:0  ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;LABEL_REAL_ENTRY:    ; 从保护模式跳回到实模式就到了这里mov    ax, csmov    ds, axmov    es, axmov    ss, axmov    sp, [SPValueInRealMode]in al, 92h  ; ┓and    al, 11111101b   ; ┣ 关闭 A20 地址线out    92h, al  ; ┛sti     ; 开中断mov    ax, 4c00h   ; ┓int    21h  ; ┛回到 DOS
; END of [SECTION .s16]

[SECTION .s32]; 32 位代码段. 由实模式跳入.

[BITS   32]LABEL_SEG_CODE32:mov    ax, SelectorDatamov    ds, ax   ; 数据段选择子mov    ax, SelectorVideomov    gs, ax   ; 视频段选择子mov    ax, SelectorStackmov    ss, ax   ; 堆栈段选择子mov    esp, TopOfStack; 下面显示一个字符串mov    ah, 0Ch  ; 0000: 黑底    1100: 红字xor    esi, esixor    edi, edimov    esi, OffsetPMMessage    ; 源数据偏移mov    edi, (80 * 10 + 0) * 2  ; 目的数据偏移。屏幕第 10 行, 第 0 列。cld
.1:lodsbtest   al, aljz .2mov    [gs:edi], axadd    edi, 2jmp    .1
.2: ; 显示完毕call   DispReturn

; ; 以下代码分步骤演示了如何将A的堆栈拷贝到B的堆栈(A==调用者,B=被调用者)
; 1.将ring3的堆栈段描述符的选择子压栈 [add]

 push   SelectorStack3

; 2.将ring3的堆栈压栈 [add]

 push   TopOfStack3 

; 3.将ring3的堆栈值 压栈 [add]

 push   SelectorCodeRing3push   0   

; 4.retf 弹出ip + 弹出cs;此时ip==0, cs==SelectorCodeRing3,然后CPU自动解析出SelectorCodeRing3 索引(定位)的段描述符, 该描述符存储有
; 4.ring3下代码段LABEL_CODE_RING3 的基地址, 让我们转向 代码末尾的 LABEL_CODE_RING3 代码段吧;

 retf; 测试调用门(无特权级变换),将打印字母 'C'call   SelectorCallGateTest:0;call  SelectorCodeDest:0; Load LDTmov    ax, SelectorLDTlldt   axjmp    SelectorLDTCodeA:0  ; 跳入局部任务,将打印字母 'L'。; ------------------------------------------------------------------------
DispReturn:push   eaxpush   ebxmov    eax, edimov    bl, 160div    bland    eax, 0FFhinc    eaxmov    bl, 160mul    blmov    edi, eaxpop    ebxpop    eaxret
; DispReturn 结束---------------------------------------------------------SegCode32Len    equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]

[SECTION .sdest]; 调用门目标段

[BITS   32]LABEL_SEG_CODE_DEST:mov    ax, SelectorVideomov    gs, ax   ; 视频段选择子(目的)mov    edi, (80 * 12 + 0) * 2  ; 屏幕第 12 行, 第 0 列。mov    ah, 0Ch  ; 0000: 黑底    1100: 红字mov    al, 'C'mov    [gs:edi], axretfSegCodeDestLen  equ $ - LABEL_SEG_CODE_DEST
; END of [SECTION .sdest]

; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
[SECTION .s16code]

ALIGN   32
[BITS   16]
LABEL_SEG_CODE16:; 跳回实模式:mov    ax, SelectorNormalmov    ds, axmov    es, axmov    fs, axmov    gs, axmov    ss, axmov    eax, cr0and    al, 11111110bmov    cr0, eaxLABEL_GO_BACK_TO_REAL:jmp    0:LABEL_REAL_ENTRY  ; 段地址会在程序开始处被设置成正确的值Code16Len   equ $ - LABEL_SEG_CODE16; END of [SECTION .s16code]

; LDT
[SECTION .ldt]

ALIGN   32
LABEL_LDT:
;                                         段基址       段界限     ,   属性
LABEL_LDT_DESC_CODEA:   Descriptor         0,     CodeALen - 1,   DA_C + DA_32  ; Code, 32 位LDTLen   equ    $ - LABEL_LDT; LDT 选择子
SelectorLDTCodeA    equ LABEL_LDT_DESC_CODEA    - LABEL_LDT + SA_TIL
; END of [SECTION .ldt]

; CodeA (LDT, 32 位代码段)
[SECTION .la]

ALIGN   32
[BITS   32]
LABEL_CODE_A:mov    ax, SelectorVideomov    gs, ax   ; 视频段选择子(目的)mov    edi, (80 * 13 + 0) * 2  ; 屏幕第 13 行, 第 0 列。mov    ah, 0Ch  ; 0000: 黑底    1100: 红字mov    al, 'L'mov    [gs:edi], ax; 准备经由16位代码段跳回实模式jmp    SelectorCode16:0
CodeALen    equ $ - LABEL_CODE_A
; END of [SECTION .la]

; CodeRing3的定义(ring3下的代码段)
; 显然, ring3 中的任务执行完后, jmp $ 这句代码使得程序 就会 永久停留在该处;

[SECTION .ring3]
ALIGN   32
[BITS   32]
LABEL_CODE_RING3:mov    ax, SelectorVideomov    gs, axmov    edi, (80 * 14 + 0) * 2mov    ah, 0Chmov    al, '3'mov    [gs:edi], axjmp    $
SegCodeRing3Len equ $ - LABEL_CODE_RING3
; END of [SECTION .ring3]



【总结-Conclusion】

  • C1)实现ring0 jmp 到ring3, 使用的是ret 指令,代码如下:(核心代码)

    ; 以下代码分步骤演示了如何将A的堆栈拷贝到B的堆栈(A==调用者,B=被调用者)
    ; 1.将ring3的堆栈段描述符的选择子压栈 [add](堆栈段描述符 存储有新堆栈的基地址ss)

    push    SelectorStack3
    

    ; 2.将ring3的堆栈压栈[add](新栈顶指针esp压栈)

    push    TopOfStack3
    

    ; 3.将ring3的堆栈值 压栈 [add] (将ring3 下的任务代码段基地址cs 压栈)

    push    SelectorCodeRing3
    ;   (偏移量ip == 0 压栈)push   0  
    

; 4.retf 弹出ip + 弹出cs;此时ip==0, cs==SelectorCodeRing3,然后CPU自动解析出SelectorCodeRing3 索引(定位)的段描述符, 该描述符存储有
; 4.ring3下代码段LABEL_CODE_RING3 的基地址;

 retf

要知道: retf == [ pop cs, pop ip ] , ret == pop ip

  • C2)指令ret 用于执行近返回、同特权级远返回和不同特权级的远返回;
  • C2.1)近返回仅在当前代码段中转移程序控制权, 因此CPU 仅仅进行界限检查;
  • C2.2)对于同特权级远返回, CPU同时从堆栈中弹出返回代码段的选择子和返回指令指针;
  • C2.3)会发生特权级改变的远返回仅允许返回到低特权级程序中, 即返回到的代码段DPL要大于CPL;

  • 当执行远返回时, CPU执行以下步骤(也即是上述过程的第4步——指令retf):

  • 1)检查保存的cs 中的RPL 以判断返回时是否要变换特权级;
  • 2)加载被调用者堆栈上的cs 和eip;
  • 3)如果ret 指令含有参数,则增加esp 跳过参数,然后esp 将指向被保存过的调用者ss 和 esp ;ret的参数个数对应 调用门中的 Param Count的值;
  • 4)加载ss 和 esp , 切换到调用者堆栈,被调用者的ss 和 esp 被丢弃;
  • 5)如果ret 指令含有参数, 增加esp 的值以跳过参数;
  • 6)检查ds、es、fs、gs的值,如果其中哪一个寄存器指向的段的DPL 小于CPL(此规则不适用于一致代码段),那么一个空描述符会被加载到该寄存器;


    这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

aws 删除ec2实例_如何在AWS中启动EC2实例

aws 删除ec2实例你好朋友&#xff0c; 在本教程中&#xff0c;我们将看到如何立即在AWS中旋转EC2实例。 您应该有权访问AWS控制台。如果您还没有AWS账户&#xff0c;则可以单击此处并在AWS上创建免费套餐。 如何在AWS中启动EC2实例 第1步 &#xff1a; 使用您的凭证登录到您…

python足球射门小游戏_足球射门游戏教案

足球射门游戏教案【篇一&#xff1a;足球射门游戏教案】足球游戏教案任课教师&#xff1a;张旭授课班级&#xff1a;初二(1)班第1次课上课时间&#xff1a;2008-12-1人数&#xff1a;50男(30)女(20)指导教师&#xff1a;彭老师1.运球接力1.足球运球类游戏{ 2.传球射门3.足球打靶…

jQuery 1.9版本之后函数toggle()的轮流执行事件监听器功能被舍弃掉了

文章目录实现隐藏与显示相互切换的效果可以恢复函数 toggle 轮流执行事件监听器的功能toggle()方法主要有两个功能&#xff0c;一是用于绑定两个或多个事件处理器函数&#xff0c;在元素被点击时轮流执行&#xff1b;二是切换元素的显隐状态&#xff0c;如果元素是可见的&#…

不同特权级间代码段的跳转{ 门 + 跳转(jmp + call) + 返回(ret) }

【0】写在前面 0.1&#xff09;我们讲 CPU的保护机制&#xff0c;它是可靠的多任务运行环境所必须的&#xff1b;0.2&#xff09; CPU保护机制&#xff1a;分为段级保护 页级保护&#xff1b; 0.2.1&#xff09;段级保护分为&#xff1a;段限长 limit 检查、段类型 type 检查…

精打细算油盐_Java:ChronicleMap第1部分,精打细算

精打细算油盐用数百万个对象填充HashMap会很快导致诸如内存使用效率低下&#xff0c;性能低下和垃圾回收等问题。 了解如何使用堆外CronicleMap &#xff0c;其中可以包含数十亿个对象&#xff0c;而对堆的影响很小或没有。 当我们要使用中小型数据集时&#xff0c;内置的Map实…

日志服务器搭建及配置_[ELK入门到实践笔记] 一、通过rsyslog搭建集中日志服务器...

ELK 是elastic公司提供的一套完整的日志收集以及展示的解决方案&#xff0c;这是我在ELK学习和实践过程写下的笔记&#xff0c;整理成了一个ELK入门到实践的系列文章&#xff0c;分享出来与大家共勉。本文为该系列文章的第一篇&#xff0c;通过rsyslog搭建集中日志服务器&#…

JavaScript(JS)调用事件监听器(事件处理函数/事件处理程序/事件监听函数)时如何传递参数

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>事件的演示代码</title></head> <body> <input id"bt" type"button" value"test"> <scrip…

x86 的 TSS 任务切换机制

转自&#xff1a;http://blog.chinaunix.net/uid-587665-id-2732907.html 【0】写在前面segment descriptors 构建保护模式下的最基本、最根本的执行环境。system descriptors 则构建保护模式下的核心组件&#xff1a;&#xff11;、TSS descriptor 提供硬件级的进程切换机制&a…

spring安全性_具有PreAuthorize的Spring方法安全性

spring安全性朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户&#xff1f; 立即尝试Okta的API和Java SDK。 数分钟之内即可在任何应用程序中对用户进行身份验证&#xff0c;管理和保护。 本教程将探讨使用Spring Security在Spring Boot中配置身份验证和授权的两种方法。…

animiz动画制作软件_AN动画制作软件

AN基础介绍我们先了解一些基本概念&#xff0c;才能帮助我们更好的进行下面一系列的操作。1.图层。图层就像是含有文字或图形等元素的胶片&#xff0c;一张张按顺序叠放在一起&#xff0c;组合起来形成页面的最终效果。图层可以将页面上的元素精确定位。图层中可以加入文本、图…

关于一致/非一致代码段与TSS 关系的个人看法

【0】概念定义 0.1&#xff09;一致代码段: 简单理解&#xff0c;就是操作系统拿出来被共享的代码段,可以被低特权级的用户直接调用访问的代码&#xff0c; 但是特权级高的程序不允许访问特权级低的数据. 通常这些共享代码&#xff0c;是”不访问”受保护的资源和某些类型异…

python预处理标准化_tensorflow预处理:数据标准化的几种方法

tensorflow预处理&#xff1a;数据标准化的几种方法发布时间&#xff1a;2018-08-09 19:39,浏览次数&#xff1a;1774, 标签&#xff1a;tensorflow数据归一化问题是数据挖掘中特征向量表达时的重要问题&#xff0c;当不同的特征成列在一起的时候&#xff0c;由于特征本身表达方…

三思笔记_使用反射前先三思

三思笔记介绍 有时&#xff0c;作为开发人员&#xff0c;您可能会遇到无法使用new运算符实例化对象的情况&#xff0c;因为其类名称存储在配置XML中的某个位置&#xff0c;或者您需要调用一个名称指定为注释属性的方法。 在这种情况下&#xff0c;您总会有一个答案&#xff1a;…

分页机制总结

【0】写在前面&#xff08;分页机制&#xff09; 0.0&#xff09; source code from orange’s implemention of a os and text description from Zhaojiong’s perfect analysis of Linux kernel and for complete code ,please visit https://github.com/pacosonTang/Orange…

python程序填空题参照代码模板、完善代码_python二级考试操作题11.pdf

综合应用题参照代码模板完善代码&#xff0c;实现下述功能。文件ngchina.html 保持了网页源代码&#xff0c;请将该页面中图片的URL 提取出来,并输出所有图像的URL。习题讲解#P301#读取HTML 文件内容def getHTMLlines(htmlpath):f open(htmlpath,"r",encoding utf-…

Struts2学习笔记

文章目录Struts2 的核心开发包Struts2 配置文件Struts2 域对象Struts2 编程流程Action 组件使用通配符配置 ActionAction 中如何访问 Session通过 ActionContext 对象访问 Session 对象&#xff08;不推荐&#xff09;通过实现 SessionAware 接口访问 sessionAction 如何访问 r…

如何从文件系统中读取文件内容

【0】写在前面 0.0&#xff09; text description from orange’s implemention of a os &#xff0c;文末总结系个人臆测出的干货 【1】intro to FAT12&#xff08;file allocation table 12&#xff09;文件系统格式&#xff08;from Baidu Baike&#xff09; &#xff08;…

java微服务,微在哪_Java:ChronicleMap第3部分,快速微服务

java微服务,微在哪标准Java Maps需要在启动时进行初始化。 了解如何利用可从文件初始化的ChronicleMaps并显着减少微服务启动时间&#xff0c;以及如何在JVM之间共享Maps。 内置的Map实现&#xff08;例如HashMap和ConcurrentHashMap速度很快&#xff0c;但是必须先使用映射进…

excel离散度图表怎么算_Excel数据分析——离散值排除-excel直方图

今天举例的数据继续沿用昨天做出来的结果&#xff0c;至于这组数据还要接着用多久~~可能要混到我讲不下去为止吧~~~我们通过两个不同的拟合公式得到了两组不同的残差值&#xff0c;数据情况如下&#xff1a;有没有觉得看上面那张散点图有点糊啊&#xff1f;没错&#xff0c;问题…

drools dmn_Drools DMN最新开源引擎性能改进

drools dmn我们一直在寻求改善Drools DMN开源引擎的性能。 我们最近审查了DMN用例&#xff0c;其中输入数据节点的实际输入总体有所不同。 这突出显示了引擎的次佳性能&#xff0c;我们在最新版本中对此进行了改进。 我想分享我们的发现&#xff01; 基准制定 当我们开始为此用…