Assembly 指令获取访问传递锁定的指令

Assembly 指令获取访问传递锁定的指令,assembly,concurrency,x86,thread-safety,x86-64,Assembly,Concurrency,X86,Thread Safety,X86 64,《英特尔软件开发人员手册》提到“指令获取和页表访问可以传递锁定指令”。这意味着什么,为什么重要 有一篇文章说,许多Windows函数都是以MOV EDI,EDI指令开始的,因为它对于安全的代码挂接非常有用:它可以用两个字节的相对跳转来自动替换。但是,如果对内存的获取访问可以“传递锁定指令”,那么是否可能发生以下情况 cpu 0以原子方式将MOV EDI、EDI指令替换为相对跳转 cpu 1“传递锁定指令”,获取并执行陈旧的MOV EDI,EDI 这样的事情也可能发生吗 cpu 0以原子方式

《英特尔软件开发人员手册》提到“指令获取和页表访问可以传递锁定指令”。这意味着什么,为什么重要

有一篇文章说,许多Windows函数都是以
MOV EDI,EDI
指令开始的,因为它对于安全的代码挂接非常有用:它可以用两个字节的相对跳转来自动替换。但是,如果对内存的获取访问可以“传递锁定指令”,那么是否可能发生以下情况

  • cpu 0以原子方式将
    MOV EDI、EDI
    指令替换为相对跳转
  • cpu 1“传递锁定指令”,获取并执行陈旧的
    MOV EDI,EDI
这样的事情也可能发生吗

  • cpu 0以原子方式将
    MOV EDI、EDI
    指令替换为相对跳转
  • 由于指令回迁可以“传递锁定的指令”,因此从指令回迁的上下文中可以认为指令的替换是非原子的,因此cpu 1从陈旧指令中回迁1字节,从新指令中回迁1字节
摘自《英特尔64和IA-32体系结构软件开发人员手册》第3卷:“系统编程指南”

锁定操作是相对于所有其他内存的原子操作 操作和所有外部可见事件仅获取指令 页表访问可以传递锁定的指令。锁定 指令可用于同步由一个处理器写入的数据 并由另一个处理器读取

对于P6系列处理器,锁定操作序列化所有 未完成的加载和存储操作(即,等待它们 完成)。对于奔腾4和英特尔至强,这一规则同样适用 处理器,只有一个例外。加载弱引用的操作 有序内存类型(如WC内存类型)可能不可用 连载


链接:

关于第二种情况——“传递锁定指令”并不意味着它破坏了原子性。如果存储以原子方式写入这2个指令字节,则在任何时候都无法仅看到其中一个(存储将在完整缓存线上运行-请注意,如果将2个字节拆分为2行,则不会是原子的)。它的意思是,为了尝试同步而输入的任何锁指令都不会阻止代码获取,因此就内存顺序而言,它可以发生在同步之前或之后

现在,关于第一个场景和一般问题,请注意,您的描述中没有锁定。您所描述的情况是完全有效的,即使它是数据读取而不是代码读取-除了您自己强制执行的以外,两个核心之间没有固有的顺序。为了执行这样的命令,您可以开始使用屏障、信号量或任何其他方法,最终会归结为一些锁阻塞cpu 1,直到cpu 0发出写操作完成的信号

在这种情况下,数据读取将被锁暂停,但较年轻的代码读取实际上可以获取旧数据,尽管您试图保护它。然而,这里有一种机制x86内核通常实现称为SMC(自修改代码)刷新-cpu 0的存储嗅探cpu 1中的指令缓存,检测那里的陈旧代码,因为它无法确切地知道该代码在管道中的位置,或者可能已经产生了什么影响(据我们所知,可能会有一个暂停指令,或者更糟的情况)-它只会刷新整个管道。不同产品的确切细节可能不同,但概念非常古老


页面漫游的情况稍微复杂一点,但这里还有一种机制,可以在使用过程中检测大多数修改情况-查找“TLB分解”。请注意,在某些情况下,SMC和TLB在运行过程中的修改都是完全有效的,并起到了一定的作用(SMC通常用于JITting,页面移动是在进程之间传递数据的一种廉价方式,无需复制数据。

我不确定您问题中的不同语句如何组合在一起。我认为重要的是:1.您希望能够插入一条双字节跳转指令。2.插入该指令的位置也有是一条双字节指令;它不能是,比如说,两个连续的,一个字节的NOP,因为执行可能在覆盖指令之前执行了第一条单字节指令,然后获取了一个被撕碎的后半部分。锁定的内存访问似乎与此无关。很清楚为什么指令会获取和页面漫游s被排除在必须序列化的范围之外,这会使它们太慢,并迫使CPU添加昂贵的硬件来比较它们的地址和缓冲存储。另一方面,在大多数多线程场景中,它们对保护并不重要。感谢您的评论,Kerrek SB。我更新了这个问题,试图让我更清楚地了解我的想法“我想知道。谢谢你的详细回答!对于可能性1,我想指令缓存窥探将仅限于当前处理器,但这表明我对所有这些知之甚少。对于可能性2,我不确定我在想什么,但你关于为什么永远不会发生的解释是有意义的。考虑到你的解释,当使用交叉修改代码时,如果CPU支持自嗅探,那么在x86和x86-64处理器上就不需要像CPUID这样的串行化指令了?而大多数现代x86和x86-64 CPU都支持这一点?@Jason:我建议阅读题为“处理自修改和交叉修改代码”的部分“在您最喜欢的《英特尔开发人员手册》(第3卷第8.1.3节,关于我碰巧最先获取的手册版本,可能是较新或较旧版本手册中的另一节)。对于交叉修改代码,您需要等待更新,然后是s