【问题标题】:How can I mitigate the impact of the Intel jcc erratum on gcc?如何减轻英特尔 jcc 勘误表对 gcc 的影响?
【发布时间】:2020-07-30 01:41:42
【问题描述】:

如果我有一个受Intel jcc erratum 约束的芯片,我如何在 gcc 中启用缓解(调整分支位置以避免有问题的对齐),以及哪些 gcc 版本支持它?

【问题讨论】:

    标签: gcc x86 intel gnu-assembler compiler-flags


    【解决方案1】:

    通过编译器:


    GNU 工具链在汇编器中使用as -mbranches-within-32B-boundaries 进行缓解,从而启用 (GAS manual: x86 options):

    • -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 的策略似乎是在最后一个对齐指令(例如.p2align)之后或在可以结束之前 32B 边界的最后一个 jcc/jmp 之后尽早填充。我想这最终可能会在外部循环中填充,在内部循环之前或之后,也许可以帮助它们适应更少的 uop 缓存行? (Skylake 还禁用了其 LSD 循环缓冲区,因此在两个 uop 缓存行之间拆分的微小循环每次迭代最多可以运行 2 个周期,而不是 1 个。)

    它会导致大量的填充和长的宏融合跳转,例如-fstack-protector-strong,在最近的 GCC 使用 sub rdx,QWORD PTR fs:0x28 / jnz(早期的 GCC 曾经使用 xor,它可以'即使在英特尔上也不会融合)。 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 以优化手写 asm,例如 mov $1, %rax => mov $1, %eax / xor %rax,%rax => %eax / test $1, %eax => al 甚至 EVEX => VEX 用于 vmovdqa64 => vmovdqa 之类的东西。

    还有像-msse2avx这样的东西,即使助记符不是v...,也总是使用VEX前缀,-mfence-as-lock-add=yesmfence组装成lock addl $0x0, (%rsp),甚至-momit-lock-prefix=yes可以用来构建std ::单处理器系统的原子代码。

    as 还具有 CPU 功能级别检查,例如 -march=znver3.arch 指令。还有-mtune=CPU,尽管 IDK 是做什么的。或许设置 NOP 策略?

    【讨论】:

      猜你喜欢
      • 2020-09-30
      • 2023-03-31
      • 2011-07-01
      • 1970-01-01
      • 2017-05-08
      • 1970-01-01
      • 2018-08-26
      • 2016-08-27
      • 1970-01-01
      相关资源
      最近更新 更多