阅读有关内存保护密钥(MPK)的英特尔SDM并不建议将wrpkru
指令视为序列化或隐式强制执行内存排序。
首先,如果它不执行某种排序是令人惊讶的,因为人们会怀疑程序员不希望乱序执行wrpkru
周围的内存访问。
第二,这是否意味着wrpkru
需要被lfence
包围?
答案 0 :(得分:2)
我假设CPU像往常一样保留了以程序顺序运行单个线程的错觉。那是无序执行的基本规则。使用旧的PKRU完成wrpkru
之前的访问,使用新的PKRU完成之后的访问。
就像修改MXCSR如何影响以后的FP指令,而不影响早期的指令一样,或者修改段寄存器如何影响以后的但不更早的加载/存储。
是否要重命名PKRU,MXCSR或段寄存器取决于实现。如果未重命名PKRU,则它必须先完成所有待处理的加载/存储,然后再更改PKRU并允许以后的加载/存储执行。 (也就是说,wrpkru
的微代码可以包括lfence
的微指令,如果这样做的话。)
所有内存访问都依赖于最后一条wrpkru
指令,最后一次写入相关段寄存器,最后一次写入cr3
(顶层页表)以及特权级别的最新更改(syscall
/ iret
/其他)。同样,在该位置的最后一家商店,您也不需要围栏就可以看到自己最近的商店。由CPU架构师来构建可以在保持程序顺序错觉的同时快速运行的硬件。
例如至少从Core2起,Intel CPU已重命名了x87 FP控制字,因此通过将x87舍入模式更改为截断然后返回最近的值来实现(int)fp_var
的旧二进制文件不会序列化FPU。根据Agner Fog的测试,某些CPU确实重命名了段寄存器,但是我的测试表明Skylake没有:Is a mov to a segmentation register slower than a mov to a general purpose register?。
我对MPK并不熟悉,但是为什么只要它们都使用正确的PKRU值,并且不违反x86的任何正常内存顺序,内存访问就会出现乱序的问题规则?
(其他线程只允许对StoreLoad重新排序。在内部,CPU可以比“应有”执行更早的加载,但是请确保在体系结构允许的点之前没有使高速缓存行无效装载。 这就是内存顺序缓冲区的作用。)
在C / C ++ 中,您当然需要某种方式来阻止围绕包装函数的访问在编译时重新排序。通常,非内联函数调用就足够了,例如pthread_mutex_lock()
。 How does a mutex lock and unlock functions prevents CPU reordering?。
此答案的较早部分是关于组装中的订购。