首页 > 解决方案 > 当前指令旁边的 RIP 相关加载会发生什么?缓存命中?

问题描述

我正在阅读 Agner Fog 关于 x86 汇编的书。我想知道 RIP 相对寻址在这种情况下是如何工作的。具体来说,假设我的 RIP 偏移量是 +1。这表明我要读取的数据就在内存中这条指令的旁边。

这条数据很可能已经被提取到 L1 指令缓存中。假设这些数据也不在 L1d 中,那么 CPU 上究竟会发生什么?

让我们假设它是一个相对较新的英特尔架构,如 Kaby Lake。

标签: assemblyx86x86-64cpu-architecturecpu-cache

解决方案


是的,它在 L1i 缓存和 uop 缓存中可能很热。该页面在 L1iTLB 中也很热门。但这一切都与数据加载无关。

由于指令提取,它可能在 L2 中很热,但从那时起它可能已被驱逐(L2 是 NINE wrt。L1 缓存)。 所以最好的情况是 L2 的成功

L1iTLB 和 L1dTLB 是分开的,因此如果这是从该页面加载的第一个数据,它将在 L1dTLB 中丢失。如果统一的 2 级 TLB 是受害者缓存,它可能会错过那里,甚至触发页面遍历,尽管在 L1iTLB 中很热,但我不知道 L2TLB 在最近的 Intel CPU 中是否真的是受害者缓存。不过,这是有道理的;同一页面中的代码和数据通常很少见。(虽然比同一行中的代码和数据少。)

另请参阅为什么编译器将数据放入 PE 和 ELF 文件的 .text(code) 部分以及 CPU 如何区分数据和代码?一些细节和讨论。但请注意,这是一个错误的说法,编译器不会在 x86 上这样做,因为它与有助于性能相反(浪费 TLB 覆盖范围和浪费缓存容量),不像在 ARM 上,函数之间的常量池是正常的,因为 PC 相对寻址范围非常有限。只有一些混淆器可能会这样做。


具体来说,假设我的 RIP 偏移量是 +1。这表明我要读取的数据就在内存中这条指令的旁边

rel32相对于当前指令的结尾。所以不,不是在旁边;那将是一个 1 字节的间隙。

例如像这样:

              movzx eax, byte [rip + 1]  
              ret
                            ; could be a page boundary here
load_target:  int3        ; db 0xcc

请注意[RIP+1],如果指令在页面边界的 0 或 1 个字节内结束,则它可能位于与使用该寻址模式的指令不同的高速缓存行甚至页面中。

那 1 个字节甚至可能是 a ret,因此该指令可能已经在执行,而前端已经(或曾经)从其他行或页面获取,就像它本来应该有的那样。我认为您对从包含当前指令的同一行获取的情况更感兴趣。不妨说从当前指令的机器代码mov eax, [RIP - 4]中获取rel32 本身。-4

加载不会触发自修改代码管道核弹,只会触发存储,所以这很好。


推荐阅读