Bee*_*ope 9 x86 gcc intel compiler-flags
如果我有一个受Intel jcc erratum约束的芯片,我如何在 gcc 中启用缓解(它调整分支位置以避免有问题的对齐),以及哪些 gcc 版本支持它?
通过编译器:
-Wa,-mbranches-within-32B-boundaries-mbranches-within-32B-boundaries直接编译选项,而不是-Wa./QIntel-jcc-erratum请参阅英特尔 JCC 勘误表 - 用于缓解的前缀有什么影响?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(每个 insn 最多 5 个段前缀)。所以相关的 GCC 调用是 gcc -Wa,-mbranches-within-32B-boundaries
不幸的是,GCC-mtune=skylake不启用此功能。
GAS 的策略似乎是在最后一个对齐指令(例如 )之后或在可以在32B 边界之前.p2align结束的最后一个 jcc/jmp 之后尽早进行填充。我猜想最终可能会在内循环之前或之后在外循环中进行填充,也许可以帮助它们适应更少的 uop 缓存行?(Skylake 还禁用了 LSD 循环缓冲区,因此跨两个 uop 缓存行的微小循环每次迭代最多可以运行 2 个周期,而不是 1 个。)
它可能会导致相当大量的带有长宏融合跳转的填充,例如-fstack-protector-strong最近的 GCC 使用sub  rdx,QWORD PTR fs:0x28/ jnz  (早期的 GCC 使用xor,即使在 Intel 上也无法融合)。sub + jnz 总共 11 个字节,因此在最坏的情况下可能需要 11 个字节的 CS 前缀才能将其移动到新的 32B 块的开头。显示之前 insns 中的 8 个 CS 前缀的示例:https://godbolt.org/z/n1dYGMdro
GCC 不知道指令大小,它只打印文本。这就是为什么它需要 GAS 支持诸如.p2align 4,,10按 16 对齐之类的内容(如果需要少于 10 个字节的填充),以实现它想要使用的对齐启发式方法。(通常后面跟着.p2align 3表示无条件对齐 8。)
as还有其他默认情况下未启用的有趣选项,例如-Os优化手写汇编,如mov $1, %rax=> mov $1, %eax/ xor %rax,%rax=> %eax/ test $1, %eax=>al甚至 EVEX => VEX 等 vmovdqa64 => vmovdqa 之类的东西。
另外,-msse2avx即使助记符不是,也始终使用 VEX 前缀v...,-momit-lock-prefix=yes这可以用于为单处理器系统构建 std::atomic 代码。
并-mfence-as-lock-add=yes组装mfence成lock addl $0x0, (%rsp). 但疯狂的是,它也对sfence和 Even执行此操作lfence,因此它在lfence用作执行屏障的代码中无法使用,而这是 的主要用例lfence。例如对于 retpolines 或像这样的计时lfence;rdtsc。
as还具有 CPU 功能级别检查,-march=znver3例如 或.arch指令。而且-mtune=CPU,尽管我不知道那是做什么的。也许设定 NOP 策略?