【发布时间】:2021-08-31 10:50:02
【问题描述】:
我试图了解 CPU 管道的“获取”阶段如何与内存交互。
假设我有这些说明:
4: bb 01 00 00 00 mov $1,%ebx
9: bb 02 00 00 00 mov $2,%ebx
e: b3 03 mov $3,%bl
如果 CPU1 将 00 48 c7 c3 04 00 00 00 写入内存地址 8(即 64 位对齐)而 CPU2 正在执行这些相同的指令会发生什么?指令流会自动从 2 条指令变为 1 条指令,如下所示:
4: bb 01 00 00 00 mov $1,%ebx
9: 48 c7 c3 04 00 00 00 mov $4,%rbx
由于 CPU1 正在写入 CPU2 正在读取的同一内存,因此存在争用。
写入会导致 CPU2 管道在刷新其 L1 缓存时停止吗?
假设 CPU2 刚刚完成了对mov $2 的“获取”pĥase,为了重新获取更新的内存,会被丢弃吗?
另外还有将 2 条指令变为 1 条指令时的原子性问题。
我找到了这个quite old document 提到“指令获取单元在每个时钟周期从指令高速缓存存储器中获取一个 32 字节的高速缓存行” 我认为这可以解释为每条指令都从 L1 获取缓存行的新副本,即使它们共享相同的缓存行。 但我不知道这是否/如何适用于现代 CPU。
如果上述情况正确,则意味着在将mov $2 提取到管道后,下一次提取可能会在地址e 处获取更新值并尝试执行00 00 (add %al,(%rax)),这将可能会失败。
但如果mov $2 的提取将mov $3 带入“指令缓存”,会不会
认为下一次提取只会从该缓存中获取指令(并返回mov $3)而不重新查询 L1 是否有意义?
这将有效地使这 2 条指令的获取原子化,只要它们共享一个缓存行。
那是什么?基本上有太多的未知数,太多我只能推测,所以我非常感谢管道的 2 个获取阶段如何与它们访问的内存交互(变化)的逐个时钟周期细分。
【问题讨论】:
-
这完全取决于实现。不同的处理器以不同的方式处理这种情况。
-
对于修改自己的代码的核心,请参阅:Observing stale instruction fetching on x86 with self-modifying code - 这是不同的(并且更难),因为必须对商店的无序执行进行排序从程序顺序中较早与较晚指令的代码获取。即商店必须变得可见的时刻是固定的,不像另一个核心,它只是在它发生时发生。
标签: assembly x86 pipeline cpu-architecture hotpatching