内存保护键内存重新排序

Memory Protection Keys Memory Reordering

阅读英特尔关于内存保护密钥 (MPK) 的 SDM 并不建议 wrpkru 指令作为序列化或隐式强制执行内存排序。

首先,如果它没有强制执行某种顺序,这令人惊讶,因为有人会怀疑程序员不希望围绕 wrpkru 的内存访问乱序执行。

其次,那是否意味着wrpkru需要被lfence包围?

Linux and glibc 写入后不要使用任何形式的栅栏。但这不应该包含在 SDM 中吗?

我假设 CPU 一如既往地保留了 运行 程序顺序中单个线程的错觉。这是乱序执行的基本规则。 wrpkru 之前的访问使用旧 PKRU 完成,之后的访问使用新 PKRU 完成。

就像修改 MXCSR 影响后面的 FP 指令而不影响前面的指令,或者修改段寄存器影响后面但不影响前面的指令一样 loads/stores。

是否要重命名 PKRU、MXCSR 或段寄存器取决于实现。如果它不重命名 PKRU,那么它必须在更改 PKRU 并允许稍后的 loads/stores 执行之前完成所有未决的 loads/stores。 (即 wrpkru 的微代码可以包含 lfence 的微指令,如果它是这样实现的话。)

所有内存访问都依赖于最后的wrpkru指令,最后写入相关段寄存器,最后写入cr3(顶级页table),以及最后一次更改权限级别(syscall / iret / 其他)。同样在该位置的最后一家商店,您永远不需要围栏来查看您自己最近的商店。 CPU 架构师需要构建运行速度快的硬件,同时保持程序顺序的错觉。

例如Intel CPUs 因为至少 Core2 已经重命名了 x87 FP 控制字,所以通过将 x87 舍入模式更改为截断然后返回到最近的方式来实现 (int)fp_var 的旧二进制文件不会序列化 FPU。根据 Agner Fog 的测试,一些 CPU 会重命名段寄存器,但我的测试表明 Skylake 不会:.


我不熟悉 MPK,但是只要它们都使用正确的 PKRU 值并且不违反任何 x86 的正常内存,为什么内存访问乱序会成为问题-排序规则?

(仅允许其他线程看到 StoreLoad 重新排序。在内部 CPU 可以比 "supposed to" 更早地执行加载,但请验证缓存行在此之前未失效它在架构上允许加载的点。 这就是内存顺序缓冲区的作用。)


在C/C++中,当然你需要某种屏障来防止编译时围绕包装函数的访问重新排序。通常非内联函数调用就足够了,比如 pthread_mutex_lock().

此答案的前半部分是关于组装中的订购。