如何减轻Intel jcc勘误对gcc的影响?

12
如果我的芯片受到Intel jcc错误的影响,我该如何在gcc中启用缓解措施(调整分支位置以避免问题对齐),哪些gcc版本支持它?
1个回答

7

通过编译器:


GNU工具链在汇编器中进行缓解,使用as -mbranches-within-32B-boundaries启用(GAS手册:x86选项):

  • -malign-branch-boundary=32 (关注32字节边界)。但手册表示此选项取指数而非直接的2次幂,因此可能实际上是...boundary=5.
  • -malign-branch=jcc+fused+jmp (默认选项中不包括任何+call+ret+indirect)
  • -malign-branch-prefix-size=5 (每个指令最多有5个段前缀)。

因此,相关的GCC调用为 gcc -Wa,-mbranches-within-32B-boundaries
不幸的是,GCC -mtune=skylake并没有启用这个选项。

GAS的策略似乎是在上一次对齐指令(例如.p2align)或在可以在32字节边界之前结束的最后一个jcc/jmp之后尽早进行填充。我猜这可能会导致在内部循环之前或之后,在外部循环中进行填充,从而有助于将它们适配到更少的uop高速缓存行中? (Skylake还禁用了它的LSD循环缓冲区,因此,跨越两个uop高速缓存行的微小循环每次迭代的最佳运行速度只能达到2个周期,而不是1个周期。)

当存在长的宏嵌套跳转时,比如使用 -fstack-protector-strong 时,会导致大量填充,最近的 GCC 使用 sub rdx,QWORD PTR fs:0x28 / jnz 来实现这个功能(早期版本的 GCC 使用 xor,即使在 Intel 上也无法融合)。总共需要 11 字节的 sub + jnz,所以在最坏情况下可能需要 11 字节的 CS 前缀将其移动到一个新的 32B 块的开头。例如,在它之前的指令中显示了 8 个 CS 前缀:https://godbolt.org/z/n1dYGMdro


GCC 不知道指令大小,它只打印文本。这就是为什么它需要 GAS 支持像 .p2align 4,,10 这样的东西,如果这需要少于 10 个字节的填充,则对齐到 16,以实现它想要使用的对齐启发式算法。(通常后面会跟着 .p2align 3 来无条件地对齐到 8。)

as 还有其他有趣的选项,默认情况下没有打开,比如 -Os 可以优化手写汇编,例如 mov $1, %rax => mov $1, %eax / xor %rax,%rax => %eax / test $1, %eax => al,甚至 EVEX => VEX 的内容,例如 vmovdqa64 => vmovdqa。

还有像 -msse2avx 这样的内容,即使助记符不是 v...,也总是使用 VEX 前缀,以及 -momit-lock-prefix=yes,可用于为单处理器系统构建 std::atomic 代码。

-mfence-as-lock-add=yes 可将 mfence 组装到 lock addl $0x0, (%rsp) 中。但是它同时也会对 sfence 甚至 lfence 进行相同的操作,因此它在使用 lfence 作为执行屏障的代码中无法使用,这是 lfence 的主要用例,例如 retpolines 或类似 lfence;rdtsc 的定时操作。

as 还具有 CPU 功能级别检查功能,例如 -march=znver3,或者 .arch 指令。还有 -mtune=CPU,虽然我不知道它是干什么用的。也许设置 NOP 策略?


1
截至clang-16版本,clang的支持似乎仍然相当有限。它似乎没有考虑融合,并且使用(可变长度的)nop指令而不是冗余前缀,这在至少对于少量前缀来说似乎严格更差。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接