x86 - 断点在宽松内存模型上的行为

标签 x86 breakpoints memory-barriers

Init: int x = y = 0;

thr1       thr2
----       ----
y = 1;     x = 1;    WRITE to global variables
a = x;     b = y;    READ from global variables
print(a);  print(b);

在TSO内存模型下运行的上述代码片段中,众所周知,两个线程可以同时打印0,因为CPU可以重新排序指令来执行读指令(即线程的第二行)在写入指令之前。

那么,如果我们在读指令上插入断点,并且当断点被击中时什么也不做,只是继续执行,会发生什么呢?两个线程仍然可以同时打印 0,或者断点会阻止重新排序吗?

我假设 x86-64 架构和 x86-TSO 内存模型。如果给出架构(或内存模型)之间的任何差异,我们将不胜感激。 另外,我猜硬件断点和软件断点不会对结果产生影响(因为它们都会触发异常,并且 x86 架构以类似的方式处理它们)。这个猜测正确吗?

最佳答案

我认为这是汇编的伪代码(不是可能发生大量编译时优化的 C 代码),与 https://preshing.com/20120515/memory-reordering-caught-in-the-act/ 的情况相同。其中 StoreLoad 重新排序将可见。

带有立即返回的断点处理程序的断点只是序列化指令(如 CPUID 或 IRET)的一个非常昂贵的替代方案,它确保所有先前的指令已被执行,并且所有先前的存储都被提交到一致的缓存(即耗尽存储缓冲区)。

这样做的原因是从断点返回可能会涉及 IRET ,这是一条序列化指令。 (类似于 MFENCE,但也序列化乱序执行)。

所以,是的,断点是其他线程观察到的内存重新排序的完全屏障。

这适用于硬件断点或软件断点,其中调试器必须恢复原始指令的第一个字节才能使其正常执行,而不是 0xcc int3 软件断点。

关于x86 - 断点在宽松内存模型上的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65679691/

相关文章:

c - 为什么 -O1 比 -O2 快

c++ - 从程序集中调用的 C++ 方法返回对象数据

c - 了解使用 SSE 指令进行矢量化

assembly - “rdtsc”之前的“cpuid”

css - 如何为响应式 CSS 找出合适的最小宽度和最大宽度值?

c# - 在 Visual Studio 2019 中设置但尚未绑定(bind)的断点

c++ - 多个读者可以通过获取/释放顺序与相同的作者同步吗?

c++ - 如何设置数据断点,以在 EAX 寄存器设置为特定值时中断

C11 Atomic Acquire/Release 和 x86_64 缺乏加载/存储一致性?

c++ - 在这样的单例实现中可以对两个商店进行重新排序吗?