ESC
科技 2 分钟阅读

汇编耻辱堂

本文展示了一系列在Intel和AMD CPU上通过特定指令组合触发异常高延迟的技巧,从x87浮点微码辅助、缓存行跨越锁定,到未文档化MSR和PCIe设备寄存器访问,延迟最高达8.87亿周期,堪称“汇编耻辱堂”。

来源:Hacker News

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

enter $0, $31 ; 分配0字节,嵌套深度31(最大)

得分:112周期

策略:用一个小非正规数触发FP微码辅助。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

movabsq $0x0000000000000001, %rax
movq %rax, -8(%rsp)
fldl -8(%rsp)

得分:133周期

策略:只需确保缓存行是脏的。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

clflush (%rax) ; rax -> 驻留在L3中的脏缓存行

得分:165周期

策略:使用指数0x7ff以触发微码中的“特殊值”处理;正/负、NaN/无穷似乎没有区别,就用QNaN。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

movabsq $0x7fffffffffffffff, %rax
movq %rax, -8(%rsp)
fldl -8(%rsp)
fsin

得分:257周期

策略:用movnti存储到不同缓存行,使所有写组合(write-combining)行填充缓冲区饱和,强制mfence在退休前将整个LFB写路径排空到uncore。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

movnti %r9, 0*64(%rdi) ; ×16个不同缓存行 — 使写组合LFB饱和
; …
movnti %r9, 15*64(%rdi)
mfence ; 退休前必须排空所有挂起的LFB写入

得分:326周期

策略:暂时没什么,只是看看使TLB失效需要多长时间。

竞争者:AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)

策略:通过使用非正规源操作数命中x87 FP微码辅助路径。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

fldl subnorm ; 1e-310:值 < DBL_MIN,偏置指数 = 0
faddl subnorm ; 源为非正规 → FP微码辅助

得分:677周期

策略:将lock前缀操作数对齐到跨越缓存行边界,迫使CPU断言外部总线锁,而不是使用快速的MESI缓存一致性路径。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

; split_ptr % 64 == 63 — dword跨越字节63(行N)和64–66(行N+1)
lock xaddl %r9d, (%rdi)

得分:865周期

策略:使用非正规除数,硬件将控制权交给微码辅助,辅助规范化操作数,执行除法,然后恢复架构状态。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

movabsq $0x3ff0000000000000, %rax ; 1.0(正规被除数)
movq %rax, -8(%rsp)
fldl -8(%rsp) ; ST(0) = 1.0

movabsq $0x0000002000000000, %rax ; 6.79e-313(非正规除数)
movq %rax, -8(%rsp)
fdivl -8(%rsp) ; ST(0) = 1.0 / 非正规 → FP辅助

得分:883周期

策略:使用rakefield找到延迟最高的CPUID叶子。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

策略:在紧密循环中执行,以比硬件熵池刷新更快的速度耗尽它,迫使后续调用在熵源恢复时停滞。

竞争者:Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz

策略:使用project:nightshyft识别高延迟MSR。Zen上的MCG_CTL看起来是一个赢家:可能是微码静止并在MCA错误库上跨硬件单元同步,其中一些可能在片外,需要fabric级通信,而不是简单的本地寄存器写入。

竞争者:AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)

movl $0x17b, %ecx ; MCG_CTL
wrmsr

得分:34,304周期

策略:针对跨越NIC设备寄存器边界的I/O端口,每次写入都触发设备暂停其TX DMA引擎。

竞争者:AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)

mov $0xf019, %dx
outl %eax, %dx

得分:49,857周期

策略:使用project:nightshyft识别高延迟的模型特定寄存器:VIA使用一个未文档化的寄存器0x133,响应时间出奇地高。不知道它是做什么的。

movl $0x133, %ecx ; 未文档化MSR
rdmsr

得分:161,602周期

策略:用脏行完全填满L1/L2/L3缓存,强制DRAM回写整个层级。

竞争者:AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)

策略:针对映射到ACPI PM块的I/O端口,非对齐的4字节读取解码为对该端口所在位置的多次非posted加载。

竞争者:AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)

mov $0x0413, %dx
inl %dx, %eax

得分:12,524,415周期

策略:使用mmiotic识别PCIe fabric中的高延迟死区,命中未知GPU寄存器。

竞争者:AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)

movl 0xfcc003b0, %esi

得分:443,937,696周期

策略:在MMIO空间中搜索PCIe fabric中最慢的寄存器,命中未知GPU寄存器,使用8字节MMIO读取获得两次dword寄存器访问,这技术上是不允许的,但实际有效。

竞争者:AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)

movq 0xfcc003b0, %rax

得分:887,716,864周期