使用自修改代码观察 x86 上的陈旧指令获取

2023-12-10

我被告知并从英特尔手册中读到,可以将指令写入内存,但指令预取队列已经获取了过时的指令并将执行这些旧指令。我未能成功观察到这种行为。我的方法如下。

英特尔软件开发手册第 11.6 节指出

对当前缓存在处理器中的代码段中的内存位置进行写入会导致关联的缓存行(或多行)无效。该检查基于指令的物理地址。此外,P6 系列和 Pentium 处理器还会检查对代码段的写入是否可能修改已预取以供执行的指令。如果写入影响预取指令,则预取队列无效。后一种检查基于指令的线性地址。

因此,看起来如果我希望执行过时的指令,我需要有两个不同的线性地址引用同一物理页。因此,我将一个文件内存映射到两个不同的地址。

int fd = open("code_area", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
assert(fd>=0);
write(fd, zeros, 0x1000);
uint8_t *a1 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
        MAP_FILE | MAP_SHARED, fd, 0);
uint8_t *a2 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
        MAP_FILE | MAP_SHARED, fd, 0);
assert(a1 != a2);

我有一个汇编函数,它接受一个参数,一个指向我想要更改的指令的指针。

fun:
    push %rbp
    mov %rsp, %rbp

    xorq %rax, %rax # Return value 0

# A far jump simulated with a far return
# Push the current code segment %cs, then the address we want to far jump to

    xorq %rsi, %rsi
    mov %cs, %rsi
    pushq %rsi
    leaq copy(%rip), %r15
    pushq %r15
    lretq

copy:
# Overwrite the two nops below with `inc %eax'. We will notice the change if the
# return value is 1, not zero. The passed in pointer at %rdi points to the same physical
# memory location of fun_ins, but the linear addresses will be different.
    movw $0xc0ff, (%rdi)

fun_ins:
    nop   # Two NOPs gives enough space for the inc %eax (opcode FF C0)
    nop
    pop %rbp
    ret
fun_end:
    nop

在 C 中,我将代码复制到内存映射文件中。我从线性地址调用该函数a1,但我传递了一个指针a2作为代码修改的目标。

#define DIFF(a, b) ((long)(b) - (long)(a))
long sz = DIFF(fun, fun_end);
memcpy(a1, fun, sz);
void *tochange = DIFF(fun, fun_ins);
int val = ((int (*)(void*))a1)(tochange);

如果 CPU 接收到修改后的代码,则 val==1。否则,如果执行了过时的指令(两个 nop),则 val==0。

我已在 1.7GHz Intel Core i5 (2011 macbook Air) 和 Intel(R) Xeon(R) CPU X3460 @ 2.80GHz 上运行此程序。然而,每次我都会看到 val==1 表明 CPU 总是注意到新指令。

有人经历过我想观察的行为吗?我的推理正确吗?我对手册中提到的 P6 和 Pentium 处理器以及没有提到我的 Core i5 处理器感到有点困惑。也许还有其他原因导致 CPU 刷新其指令预取队列?任何见解都会非常有帮助!


我认为,你应该检查一下MACHINE_CLEARS.SMC性能计数器(一部分MACHINE_CLEARSCPU 的事件(在 Sandy Bridge 中可用)1,用于您的 Air powerbook;也可在 Xeon(Nehalem)上使用2- 搜索“smc”)。您可以使用oprofile, perf或英特尔的Vtune找到它的值:

http://software.intel.com/sites/products/documentation/doclib/iss/2013/amplifier/lin/ug_docs/GUID-F0FD7660-58B5-4B5D-AA9A-E1AF21DDCA0E.htm

机器清除

指标描述

某些事件需要清除整个管道并在最后一条退出指令之后重新启动。该指标衡量三个此类事件:内存顺序违规、自修改代码以及对非法地址范围的某些加载。

可能的问题

执行时间的很大一部分花在处理机器清除上。检查 MACHINE_CLEARS 事件以确定具体原因。

SMC: http://software.intel.com/sites/products/documentation/doclib/stdxe/2013/amplifierxe/win/win_reference/snb/events/machine_clears.html

MACHINE_CLEARS 事件代码:0xC3 SMC掩码:0x04

检测到自修改代码 (SMC)。

检测到的自修改代码机器清除数。

Intel也谈到了smchttp://software.intel.com/en-us/forums/topic/345561(链接自英特尔性能瓶颈分析器的分类

当检测到自修改代码时会触发此事件。这通常可以被进行二进制编辑的人用来强制它采取特定的路径(例如黑客)。此事件计算程序写入代码段的次数。自修改代码会在所有 Intel 64 和 IA-32 处理器中造成严重损失。修改后的高速缓存行被写回L2 和LLC 高速缓存。此外,还需要重新加载指令,从而导致性能损失。

我想,你会看到一些这样的事件。如果是,那么 CPU 能够检测到自我修改代码的行为,并引发“机器清除”——完全重新启动管道。第一个阶段是 Fetch,它们会向 L2 缓存请求新的操作码。我对每次执行代码时的 SMC 事件的确切计数非常感兴趣 - 这将为我们提供一些有关延迟的估计。(SMC 以某些单位进行计数,其中 1 个单位假定为 1.5 个 cpu 周期 - B.6.2。 intel优化手册6)

我们可以看到英特尔说“从最后一条退役指令后重新启动”,所以我认为最后一条退役指令将是mov;并且您的 nops 已经在准备中了。但 SMC 将在 mov 退休时筹集,这将杀死管道中的所有内容,包括 nop。

SMC 引起的管道重启并不便宜,Agner 在优化装配.pdf- “17.10 自修改代码(所有处理器)”(我认为任何 Core2/CoreiX 都像这里的 PM):

修改一段代码后立即执行的损失约为 P1 19 个时钟,PMMX 31 个时钟,PPro、P2、P3、PM 150-300 个时钟。自修改代码后,P4 将清除整个跟踪缓存。 80486 和更早的处理器需要在修改代码和修改后的代码之间跳转,以便刷新代码缓存。 ...

自修改代码不被认为是良好的编程实践。仅当以下情况时才应使用它 速度的提升是巨大的,并且修改后的代码被执行了很多次,以至于 使用自修改代码的好处胜过坏处。

这里建议使用不同的线性地址来使 SMC 检测器失败:https://stackoverflow.com/a/10994728/196561- 我会尝试找到实际的英特尔文档...现在无法真正回答您真正的问题。

这里可能有一些提示:优化手册,248966-026,2012 年 4 月“3.6.9 混合代码和数据”:

将可写数据放在代码段中可能无法区分 来自自修改代码。代码段中的可写数据可能会受到影响 与自修改代码相同的性能损失。

和下一节

软件应避免写入同一 1 KB 子页中的代码页 正在执行或在正在执行的同一 2 KB 子页中获取代码 书面。此外,共享包含直接或推测执行的页面 使用另一个处理器作为数据页的代码可以触发 SMC 条件,从而导致 机器的整个管道和跟踪缓存都被清除。这是由于 自修改代码条件。

因此,可能存在一些控制可写子页面和可执行子页面的交集的原理图。

您可以尝试从其他线程进行修改(交叉修改代码)——但是需要非常小心的线程同步和管道刷新(您可能希望在编写器线程中包含一些强制延迟;同步后的 CPUID是所需要的)。但你应该知道他们已经使用“修复了这个问题”nukes“ - 查看US6857064 patent.

我对提到 P6 和 Pentium 处理器的手册有点困惑

如果您已获取、解码并执行了英特尔说明手册的某些过时版本,则这是可能的。您可以重置管道并检查此版本:订单号:325462-047US,2013 年 6 月“11.6 自修改代码”。该版本仍然没有提及有关较新 CPU 的任何信息,但提到当您使用不同的虚拟地址进行修改时,微体系结构之间的行为可能不兼容(它可能适用于您的 Nehalem/Sandy Bridge,但可能不适用于 .. Skymont)

11.6 自修改代码对当前缓存在处理器中的代码段中的内存位置进行写入会导致关联的缓存行(或多行)无效。该检查基于指令的物理地址。此外,P6 系列和 Pentium 处理器还会检查对代码段的写入是否可能修改已预取以供执行的指令。如果写入影响预取指令,则预取队列无效。后一种检查基于指令的线性地址。对于 Pentium 4 和 Intel Xeon 处理器,在代码段中写入或监听指令(其中目标指令已解码并驻留在跟踪高速缓存中)会使整个跟踪高速缓存无效。后一种行为意味着自修改代码的程序在 Pentium 4 和 Intel Xeon 处理器上运行时可能会导致性能严重下降。

实际上,对线性地址的检查不应在 IA-32 处理器之间产生兼容性问题。包含自修改代码的应用程序使用相同的线性地址来修改和获取指令。

系统软件(例如调试器)可能会使用与用于获取指令的线性地址不同的线性地址来修改指令,在执行修改的指令之前将执行串行化操作(例如 CPUID 指令),这将自动重新同步指令缓存和预取队列。 (有关使用自修改代码的更多信息,请参见第 8.1.3 节“处理自修改代码和交叉修改代码”。)

对于 Intel486 处理器,对高速缓存中的指令进行写入将在高速缓存和内存中修改该指令,但如果在写入之前预取该指令,则执行的指令可能是旧版本的指令。为了防止执行旧指令,请在修改指令的任何写入之后立即编码跳转指令来刷新指令预取单元

真实更新,谷歌搜索《SMC检测》(带引号),还有一些现代 Core2/Core iX 如何检测 SMC 的详细信息,以及 SMC 检测器中悬挂的 Xeon 和 Pentium 的许多勘误表:

  1. http://www.google.com/patents/US6237088用于跟踪管道中的飞行指令的系统和方法 @ 2001

  2. DOI 10.1535/itj.1203.03(谷歌搜索,citeseerx.ist.psu.edu 有免费版本) - Penryn 中添加了“包含过滤器”以减少错误 SMC 检测的数量; “现有夹杂物检测机制”如图9所示

  3. http://www.google.com/patents/US6405307- SMC 检测逻辑的旧专利

根据专利US6237088(图5,摘要),存在“行地址缓冲区”(具有许多线性地址,每个提取的指令一个地址——或者换句话说,缓冲区充满具有高速缓存行精度的提取的IP)。每个存储,或者每个存储的更准确的“存储地址”阶段将被送入并行比较器以检查存储是否与任何当前正在执行的指令相交。

两项专利都没有明确说明,它们会在SMC逻辑中使用物理地址还是逻辑地址...Sandy Bridge中的L1i是VIPT(虚拟索引,物理标记,标签中索引的虚拟地址和物理地址。 ) 根据http://nick-black.com/dankwiki/index.php/Sandy_Bridge这样我们就有了一级缓存返回数据时的物理地址。我认为intel可能会在SMC检测逻辑中使用物理地址。

更,http://www.google.com/patents/US6594734@ 1999(2003 年发表,请记住 CPU 设计周期约为 3-5 年)在“摘要”部分中说 SMC 现在位于 TLB 中并使用物理地址(或者换句话说 - 请不要试图愚弄SMC检测器):

使用翻译后备缓冲区检测自修改代码..[其中]存储有物理页地址snoops可以使用执行存储的物理内存地址进入记忆。 ...为了提供比地址页更细的粒度,高速缓存中的每个条目都包含 FINE HIT 位,将高速缓存中的信息与内存中页面的部分相关联。

(页面的一部分,在专利 US6594734 中称为象限,听起来像 1K 子页面,不是吗?)

然后他们说

所以监听,由将指令存储到内存中触发,可以通过将存储在指令高速缓存内的所有指令的物理地址与存储在关联的一个或多个存储器页面内的所有指令的地址进行比较来执行SMC检测。如果地址匹配,则表明内存位置已被修改。在地址匹配的情况下,指示SMC条件,指令高速缓存和指令流水线被引退单元刷新,并且从存储器取出新指令以存储到指令高速缓存中。

由于用于 SMC 检测的监听是物理的,并且 ITLB 通常接受线性地址作为输入以转换为物理地址,因此 ITLB 额外形成为物理地址上的内容可寻址存储器,并包括附加的输入比较端口(称为作为监听端口或反向转换端口)

- 因此,为了检测 SMC,它们强制存储通过探听将物理地址转发回指令缓冲区(类似的探听将从其他内核/CPU 或从 DMA 写入我们的缓存传递......),如果探听的 phys.地址与存储在指令缓冲区中的高速缓存行发生冲突,我们将通过从 iTLB 传递到退休单元的 SMC 信号来重新启动管道。可以想象在这样的从 dTLB 经 iTLB 到退休单元的监听循环中会浪费多少 cpu 时钟(它不能退休下一个“nop”指令,尽管它比 mov 更早执行并且没有副作用)。但是WAT? ITLB有物理地址输入和第二个CAM(又大又热)只是为了支持和防御疯狂和作弊的自修改代码。

PS:如果我们使用大页面(4M 或可能是 1G)怎么办? L1TLB 具有巨大的页面条目,对于 4 MB 页面的 1/4 可能存在大量错误 SMC 检测...

PPS:有一个变体,即对具有不同线性地址的 SMC 的错误处理仅出现在早期的 P6/Ppro/P2 中......

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用自修改代码观察 x86 上的陈旧指令获取 的相关文章

  • 如何将 protobuf-net 与不可变值类型一起使用?

    假设我有一个像这样的不可变值类型 Serializable DataContract public struct MyValueType ISerializable private readonly int x private readon
  • 提交后禁用按钮

    当用户提交付款表单并且发布表单的代码导致 Firefox 中出现重复发布时 我试图禁用按钮 去掉代码就不会出现这个问题 在firefox以外的任何浏览器中也不会出现这个问题 知道如何防止双重帖子吗 System Text StringBui
  • C中的malloc内存分配方案

    我在 C 中尝试使用 malloc 发现 malloc 在分配了一些内存后浪费了一些空间 下面是我用来测试 malloc 的一段代码 include
  • 单个对象的 Monogame XNA 变换矩阵?

    我读过一些解释 XNA Monogame 变换矩阵的教程 问题是这些矩阵应用于 SpriteBatch Begin matrix 这意味着所有 Draw 代码都将被转换 如何将变换矩阵应用于单个可绘制对象 就我而言 我想转换滚动背景 使其自
  • 为什么 Google 测试会出现段错误?

    我是 Google Test 的新手 正在尝试提供的示例 我的问题是 当我引入失败并设置GTEST BREAK ON FAILURE 1 或使用命令行选项 GTest 将出现段错误 我正在考虑这个例子 https code google c
  • 在 C 中初始化变量

    我知道有时如果你不初始化int 如果打印整数 您将得到一个随机数 但将所有内容初始化为零似乎有点愚蠢 我问这个问题是因为我正在评论我的 C 项目 而且我对缩进非常直接 并且它可以完全编译 90 90 谢谢 Stackoverflow 但我想
  • 在 Visual Studio 2010 中从 Fortran 调用 C++ 函数

    我想从 Fortran 调用 C 函数 为此 我在 Visual Studio 2010 中创建了一个 FORTRAN 项目 之后 我将一个 Cpp 项目添加到该 FORTRAN 项目中 当我要构建程序时出现以下错误 Error 1 unr
  • 为什么调用非 const 成员函数而不是 const 成员函数?

    为了我的目的 我尝试包装一些类似于 Qt 共享数据指针的东西 经过测试 我发现当应该调用 const 函数时 会选择它的非 const 版本 我正在使用 C 0x 选项进行编译 这是一个最小的代码 struct Data int x con
  • 标准化 UTF-8 到底是什么?

    The 重症监护室项目 http userguide icu project org transforms normalization 现在也有一个PHP库 http us php net manual en class normalize
  • DbContext 和 ObjectContext 有什么区别

    From MSDN 表示工作单元和存储库模式的组合 使您能够查询数据库并将更改分组在一起 然后将这些更改作为一个单元写回存储 DbContext在概念上类似于ObjectContext 我虽然DbContext只处理与数据库的连接以及针对数
  • 如何检测表单的任何控件的变化?

    如何检测 C 中表单的任何控件的更改 由于我在一个表单上有许多控件 并且如果表单中的任何控件值发生更改 我需要禁用按钮 我正在寻找一些内置函数 事件处理程序 属性 并且不想为此创建自定义函数 不 我不知道任何时候都会触发任何事件any控制表
  • Qt - ubuntu中的串口名称

    我在 Ubuntu 上查找串行端口名称时遇到问题 如您所知 为了在 Windows 上读取串口 我们可以使用以下代码 serial gt setPortName com3 但是当我在 Ubuntu 上编译这段代码时 我无法使用这段代码 se
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • 3 操作数 imul 指令在 ia-32 汇编中到底起什么作用?

    我正在阅读说明 imul 0xffffffd4 ebp ebx 4 eax 我对它到底在做什么感到困惑 我明白那个imul乘法 但我无法弄清楚语法 我知道并且更喜欢 Intel MASM 语法 所以我将使用它 请注意 操作数的顺序在 AT
  • 如何在非控制台应用程序中查看 cout 输出?

    输出到调试窗口似乎相当繁琐 我在哪里可以找到cout如果我正在编写非控制台信息 则输出 Like double i a b cout lt lt b lt lt endl I want to check out whether b is z
  • 按 Esc 按键关闭 Ajax Modal 弹出窗口

    我已经使用 Ajax 显示了一个面板弹出窗口 我要做的是当用户按 Esc 键时关闭该窗口 这可能吗 如果有人知道这一点或以前做过这一点 请帮助我 Thanks 通过以下链接 您可以通过按退出按钮轻松关闭窗口 http www codepro
  • 调用堆栈中的“外部代码”是什么意思?

    我在 Visual Studio 中调用一个方法 并尝试通过检查调用堆栈来调试它 其中一些行标记为 外部代码 这到底是什么意思 方法来自 dll已被处决 外部代码 意味着该dll没有可用的调试信息 你能做的就是在Call Stack窗口中单
  • C++ 条件编译

    我有以下代码片段 ifdef DO LOG define log p record p else define log p endif void record char data 现在如果我打电话log hello world 在我的代码中
  • 使用 .NET Process.Start 运行时挂起进程 - 出了什么问题?

    我在 svn exe 周围编写了一个快速而肮脏的包装器来检索一些内容并对其执行某些操作 但对于某些输入 它偶尔会重复挂起并且无法完成 例如 一个调用是 svn list svn list http myserver 84 svn Docum
  • 当从finally中抛出异常时,Catch块不会被评估

    出现这个问题的原因是之前在 NET 4 0 中运行的代码在 NET 4 5 中因未处理的异常而失败 部分原因是 try finallys 如果您想了解详细信息 请阅读更多内容微软连接 https connect microsoft com

随机推荐

  • keras中的可变长度输出

    我正在尝试在 keras 中创建一个自动编码器 其中输入和输出具有不同的时间步长 model Sequential encoder model add Embedding vocab size embedding size mask zer
  • UIButton 上的 RxSwift 和 isSelected 属性

    我有三个按钮 我希望一次只选择一个 and etc 我的方法是这样的 class MyController UIViewController IBOutlet var buttonOne UIButton IBOutlet var butt
  • 如何在 C++ 中将 atoi 函数与字符串一起使用

    这是一个基本问题 我使用 C 但不使用 C 11 现在 我想将字符串转换为整数 我是这样声明的 string s int i atoi s 但是 这显示了无法进行此类转换的错误 我查了一下互联网 发现C 11有stoi 但我想使用atoi本
  • 致命文件系统错误后如何恢复 Git?

    主服务器上的文件系统错误后恢复 git 存储库的最快路径是什么 想象一下 您的 OSS 项目的中央服务器发生故障 并且恢复后两天的所有提交都丢失了 你如何把它们拿回来 仅在所有客户端上调用 git Push 就足够了吗 或者还有什么我必须考
  • Gradle 运行 jar 时出现 NoClassDefFoundError

    我正在尝试建立一个 Gradle 项目 其中包含一些 Velocity 函数 到目前为止我有以下文件 src main java com veltes velotest java package com veltes import org
  • 扩展布局模板时 Jinja 不渲染任何内容

    我试图在页面上显示数据 但该页面完全是空的 我知道数据库中有数据 而且我知道query db函数返回正确的结果 但我不明白为什么 Jinja 没有渲染数据 是什么导致了这个问题 app route toto def toto entries
  • Chai 测试对象数组以“包含类似”对象子匹配

    好的 我尝试在这里阅读其他问题 但仍然没有找到直接的答案 如何使用 chai 断言数组中的部分对象匹配 像下面这样 var expect require chai expect var data name test value banana
  • 用于模板组合的车把助手

    我有一个 Handlebar 助手来调用模板中的模板 用法是这样的 applyTemplate subTemplateId arg1 123 arg2 abc 也可以传递html内容 applyTemplate tli a 1 b y an
  • 如何查找字符串拆分期间使用的分隔符 (VB.NET)

    假设我有一个字符串 我想根据几个字符进行拆分 例如 and 如何找出其中哪个字符分割了我的字符串 以便我可以将相同的字符添加回相关分割段的末尾 Dim linePunctuation as Integer 0 Dim myString As
  • ssh2_exec:等待进程结束才能运行下一个

    我正在使用 ssh2 exec 运行命令 但看起来它在 stream1 进程结束之前运行 stream2 如何仅在 stream1 结束后运行 stream2 问题解决了 Barmar 建议我看看 php net manual
  • 正则表达式:必须以字母或数字开头,其余可以是任何内容

    我正在尝试构建一个模式以便在验证中使用 我的目标是让第一个字符是字母或数字 其余的都是任意的 i ex A r4nd0m 9 h3ll0 b1llin6s 我想到 a zA Z0 9 解决办法是什么 谢谢你 正如我所评论的 一个字母或一个数
  • 无法使用 PHPMailer 通过 Google SMTP 发送邮件

    我正在尝试使用 Google 的 SMTP 与 PHPMailer 结合发送邮件 但我无法让它工作 这是我的代码 mail gt IsSMTP mail gt Host smtp gmail com mail gt SMTPAuth tru
  • 如何使用 WMI 列出设备类型?

    我正在使用 WMI Code Creator 生成代码来帮助列出设备管理器中显示的设备类型 我正在尝试检测是否存在以自己的类型显示在设备管理器中的调试器 例如 在我的计算机下列出 类别为计算机 磁盘驱动器 显示适配器 Jungo Jungo
  • 如何在 Windows 上使用 MinGW 构建 OpenCV 3.2.0 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 这篇文章包含了我 和其他用户 在从源代码构建库时遇到的所有问题 由于没有教程 我决定创建此类常见问题解答帖子 将所有解决方案放在一起 希望它会有所帮助 配置 OpenCV 3 2
  • 需要获取字符串中第二个破折号之后的所有内容吗?

    我有如下的字符串值 string str1 123 456 test string str1 123 456 test test string str1 123 REQ456 test string str1 123 REQ456 test
  • Scala:列表[Future]到Future[List],忽略失败的未来

    我正在寻找一种将任意长度的 Future 列表转换为 Future of 列表的方法 我正在使用 Playframework 所以最终我真正想要的是Future Result 但为了让事情变得更简单 我们只是说Future List Int
  • Java 十进制格式 - 与给定的精度一样

    我正在与DecimalFormat 我希望能够以给定的精度读取和写入小数 我正在转换为BigDecimal 本质上 我想要一个DecimalFormat它强制执行以下模式 d d 即 至少一位数字 然后可选地 小数点分隔符后跟至少一位数字
  • 在 WPF 中填充数字显示

    我有一个非常简单的位置读数 它只是一个应用了样式的 TextBlock 在那种样式中 我只是这样设置 还有比这更多的属性 但为了简洁我把它们去掉了 现在 我有一个使用这种样式的显示器 它将显示 0 0 到 30000 0 之间的数字 问题是
  • 如何让 VLC 因预取错误而关闭?

    Python 2 7 lib vlc 不断打印 00000000081257d0 prefetch stream error unimplemented query 264 in control每当有新歌响起时 p play 导致了这个问题
  • 使用自修改代码观察 x86 上的陈旧指令获取

    我被告知并从英特尔手册中读到 可以将指令写入内存 但指令预取队列已经获取了过时的指令并将执行这些旧指令 我未能成功观察到这种行为 我的方法如下 英特尔软件开发手册第 11 6 节指出 对当前缓存在处理器中的代码段中的内存位置进行写入会导致关