首页 文章

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

提问于
浏览
1

英特尔软件开发人员手册提到“指令获取和页表访问可以传递锁定的指令” . 这是什么意思,为什么重要?

有一篇帖子说许多Windows函数都以 MOV EDI, EDI 指令开头,因为它对安全代码挂钩非常有用:它可以用两个字节的相对跳转进行原子替换 . 但是如果对内存的获取访问可以"pass locked instructions",是否可能发生以下情况?

  • cpu 0原子地用相对跳转替换 MOV EDI, EDI 指令

  • cpu 1 "passes the locked instruction",获取并执行陈旧 MOV EDI, EDI

像这样的事情也会发生吗?

  • cpu 0原子地用相对跳转替换 MOV EDI, EDI 指令

  • 因为指令提取可以"pass the locked instructions",所以从指令提取的上下文中可以认为指令的替换是非原子的,所以cpu 1从陈旧指令中取出1个字节,从新指令中取出1个字节

英特尔64和IA-32架构软件开发人员手册,第3卷:“系统编程指南”

锁定操作相对于所有其他内存操作和所有外部可见事件都是原子操作 . 只有指令获取和页表访问才能传递锁定指令 . 锁定指令可用于同步由一个处理器写入并由另一个处理器读取的数据 . 对于P6系列处理器,锁定操作会序列化所有未完成的加载和存储操作(即等待它们完成) . Pentium 4和Intel Xeon处理器也适用这一规则,但有一个例外 . 引用弱有序内存类型(例如WC内存类型)的加载操作可能无法序列化 .

链接:Why do Windows functions all begin with a pointless MOV EDI, EDI instruction?

1 回答

  • 1

    关于第二种情况 - “传递锁定的指令”并不意味着它破坏了原子性 . 如果存储器以原子方式写入这两个指令字节,则在任何时候都看不到它们中的一个(存储将只在完整的高速缓存行上运行 - 请注意,如果2个字节被分成2行,则它不会是原子的) . 它的意思是你为了尝试同步而放置的任何锁定指令都不会阻止代码获取,所以在内存排序方面 - 它可以在它之前或之后发生 .

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

    在这种情况下,数据读取会被锁定停止,但是尽管您试图保护它,但较年轻的代码读取实际上可以获取旧数据 . 但是,这里有一个机制x86核心通常实现称为SMC(自修改代码)flush - 来自cpu 0的存储窥探cpu 1中的指令缓存,检测那里的陈旧代码,并且因为它无法分辨出这个代码到底在哪里沿着管道,或者可能已经产生了什么影响(因为我们知道那里可能有一个停止指令,或者更糟) - 它只是冲洗整个管道 . 不同产品的确切细节可能不同,但概念很老 .

    页面遍历情况稍微复杂一些,但是这里还有一种机制可以检测大多数使用过程中的修改情况 - 查找“TLB击落” . 请注意,在某些情况下,运行期间的SMC和TLB修改都是完全有效的并且服务于一个目的(SMC经常用于JITting,并且页面移动是在进程之间传递数据而不必复制它的便宜方式 .

相关问题