__builtin___clear_cache 是如何工作的?

Dev*_*ark 5 c++ caching built-in

通过 gcc 文档,我偶然发现了内置函数__builtin___clear_cache

— 内置函数:void __builtin___clear_cache (char *begin, char *end) 该函数用于为begin inclusive 和end exclusive 之间的内存区域刷新处理器的指令缓存。某些目标要求在修改包含代码的内存后刷新指令缓存,以获得确定性行为。

如果目标不需要指令缓存刷新,则 __builtin___clear_cache 无效。否则,要么内联发出指令以清除指令缓存,要么调用 libgcc 中的 __clear_cache 函数。

我觉得这很有趣,但令人惊讶。在很多情况下,当前堆栈的大量指令存储在 L1 缓存(指令缓存)中。因此,乍一看,这个内置函数可能会显着破坏我们程序的流程,因为它会清除堆栈中的下一条指令。

此指令是否还会重新填充 L1 缓存中的堆栈部分?

这似乎不太可能。如果没有,那么我想用户有责任使用权利beginend参数,以免破坏我们的过程。在实践中,如何找到正确beginend使用的东西?

Bas*_*tch 5

它只是在需要它们的目标处理器上发出一些奇怪的机器指令(x86 不需要)。

可以将其视为刷新指令缓存(例如在某些JIT__builtin___clear_cache库中)的“可移植”(对于 GCC 和兼容编译器)方式。

在实践中,如何才能找到正确的开始和结束的用法呢?

为了安全起见,我会在某些页面范围上使用它(例如使用sysconf(_SC_PAGESIZE)...获得),因此通常是 4Kbyte 对齐的内存范围(4Kbyte 的倍数)。否则,您需要一些特定于目标的技巧来查找缓存行宽度......

在 Linux 上,您可以读取/proc/cpuinfo并使用cache_alignment&cache_size行来获取更精确的缓存行大小和对齐方式。

顺便说一句,使用的代码__builtin__clear_cache很可能(由于其他原因)特定于目标机器,因此它具有或知道一些机器参数(并且应该包括缓存大小和对齐方式)。

  • 事实证明,x86 上*需要 `__builtin___clear_cache` 作为编译器内存屏障,以使 gcc 意识到“死”存储实际上正在编写代码,并且需要在转换为函数指针之前发生。请参阅 https://codegolf.stackexchange.com/questions/160100/the-repetitive-byte-counter/160236#160236 了解为什么我写 https://godbolt.org/g/pGXn3B,它重复 `dec eax` M 次然后附加一个“ret”。如果没有 `__builtin___clear_cache` 或像 `asm("":::"memory");` 这样的编译器内存屏障,`memset` 就会被优化掉,所以它只是对 malloc 返回的`调用`,而不先存储。 (2认同)
  • @约瑟夫没有。Gcc 知道 malloc(私有内存没有其他指针指向)。这可以在无法证明 mmap 安全的情况下进行优化。但碰巧工作!=完全安全且正确。 (2认同)