"rep; nop;" 是啥意思?在 x86 程序集中是啥意思?它与“暂停”指令相同吗?

Posted

技术标签:

【中文标题】"rep; nop;" 是啥意思?在 x86 程序集中是啥意思?它与“暂停”指令相同吗?【英文标题】:What does "rep; nop;" mean in x86 assembly? Is it the same as the "pause" instruction?"rep; nop;" 是什么意思?在 x86 程序集中是什么意思?它与“暂停”指令相同吗? 【发布时间】:2011-10-28 12:15:30 【问题描述】: rep; nop 是什么意思? 和pause指令一样吗? 和rep nop一样吗(不带分号)? 与简单的nop 指令有什么区别? 它在 AMD 和 Intel 处理器上的行为是否不同? (奖励)这些说明的官方文档在哪里?

这个问题的动机

在another question 的cmets 中进行了一番讨论后,我意识到我不知道rep; nop; 在x86(或x86-64)汇编中的含义。而且我在网上也找不到很好的解释。

我知道rep 是一个前缀,表示“重复下一条指令cx 次”(或者至少在旧的 16 位 x86 程序集中是这样)。根据这个summary table at Wikipedia,似乎rep 只能与movsstoscmpslodsscas 一起使用(但也许这个限制在较新的处理器上被删除了)。因此,我认为rep nop(不带分号)会重复nop 操作cx 次。

但是,经过进一步搜索,我变得更加困惑。似乎rep; noppause map to the exactly same opcode 和pause 的行为与nop 有点不同。一些old mail from 2005 说了不同的话:

“尽量不要烧太多电” “它相当于 'nop' 只是使用 2 字节编码。” “这对英特尔来说很神奇。就像'nop,但让另一个 HT 兄弟运行'” “在 Intel 上暂停,在 Athlon 上快速填充”

由于这些不同的意见,我无法理解正确的含义。

它在 Linux 内核中使用(在 i386 和 x86_64 上),连同这条评论:/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ 它也是 being used in BeRTOS,有同样的评论。

【问题讨论】:

相关:***.com/questions/12894078/pause-instruction-in-x86 【参考方案1】:

rep; nop 确实与pause 指令相同(操作码F390)。它可能用于不支持pause 指令的汇编程序。在以前的处理器上,这根本没有做任何事情,就像nop 一样,但在两个字节中。在支持超线程的新处理器上,它用作向处理器提示您正在执行自旋循环以提高性能的处理器。来自Intel's instruction reference:

提高自旋等待循环的性能。在执行“自旋等待循环”时,奔腾 4 或英特尔至强处理器在退出循环时会遭受严重的性能损失,因为它检测到可能的内存顺序违规。 PAUSE 指令向处理器提供代码序列是自旋等待循环的提示。处理器在大多数情况下使用此提示来避免内存顺序冲突,从而大大提高处理器性能。因此,建议在所有自旋等待循环中放置一条 PAUSE 指令。

【讨论】:

spin-wait loopbusy-wait loop一样吗?这种“改进”是否仅适用于超线程处理器? (为什么?) 是的,自旋等待循环与忙等待循环相同。该优势也适用于不支持超线程的 CPU。它可以被认为是限制流水线中(不必要的)指令的数量(而不是尝试并行执行循环的多次迭代) @Brendan,谢谢!我完全不明白,直到你说了关于并行循环迭代的事情。 @Brendan,哦,现在我明白了!这些现代处理器是superscalar,因此它们会尝试同时运行多条指令。如果这是一个忙等待循环,运行更多指令不会使其更快,因为它只是在等待另一个条件。 @Denilson:是的,超线程友好(或仅在没有 HT 的情况下省电)是一大好处,但另一个好处是在离开自旋循环时避免内存排序错误推测。如果没有pause,您的自旋循环实际上是一个管道清除速度较慢,以注意到另一个内核写入的内存位置的状态变化。【参考方案2】:

rep nop = F3 90 = pause 的编码,以及它如何在不支持 pause 的旧 CPU 上解码。


不适用于指令的前缀(lock 除外)实际上会被现有 CPU 忽略。

文档说将rep 与它不适用的指令一起使用是“保留并可能导致不可预测的行为”,因为未来 CPU 可能会将其识别为某些新指令的一部分。 一旦他们使用f3 xx 建立了任何特定的新指令编码,他们就会记录它是如何在旧 CPU 上运行的。 (是的,x86 操作码空间非常有限,以至于他们会做这样疯狂的事情,是的,它使解码器变得复杂。)

在这种情况下,这意味着您可以在自旋循环中使用pause 而不会破坏向后兼容。正如英特尔的 ISA 参考手册 entry for pause 所保证的那样,不知道 pause 的旧 CPU 会将其解码为 NOP 而不会造成任何伤害。在新 CPU 上,您可以享受省电/HT 友好性的好处,并且avoiding memory-ordering mis-speculation 当您正在旋转的内存确实发生变化并且您离开自旋循环时。


x86 tag wiki info page 上的英特尔手册和大量其他好东西的链接

另一个无意义的 rep 前缀成为新 CPU 上的新指令的情况:lzcntF3 0F BD /r。在不支持该指令的 CPU 上(在其 CPUID 中缺少 LZCNT 功能标志),它解码为rep bsr,其运行方式与bsr 相同。所以在旧 CPU 上,它会产生 32 - expected_result,并且在输入为零时是未定义的。

但是tzcntbsf 对非零输入做同样的事情,所以编译器可以并且确实使用tzcnt,即使不能保证目标CPU 会以tzcnt 运行它。 AMD CPU 速度快tzcnt,慢速bsf,在英特尔上它们都很快。只要对正确性无关紧要(您不依赖标志设置,或者在 input=0 情况下保留目标未修改行为),在支持它的 CPU 上将其解码为 tzcnt 会很有帮助.


一个无意义的rep前缀可能永远不会以不同方式解码的情况:rep ret在针对“通用”CPU时由gcc默认使用(即不针对具有-march-mtune的特定CPU,并且不针对 AMD K8 或 K10。)任何人都需要几十年才能制造出将 rep ret 解码为除 ret 之外的任何内容的 CPU,因为它存在于大多数 Linux 发行版的大多数二进制文件中。见What does `rep ret` mean?

【讨论】:

rep 前缀也被英特尔用于添加锁定省略。 不适用于指令的前缀将被忽略。 但提到重复前缀(F2HF3H)已保留并可能导致表 11-3 中的不可预测的行为。前缀对 SSE、SSE2 和 SSE3 指令的影响。因此,对于某些指令,前缀应用程序被忽略,而不是全部。那么这个特性是否被认为是无证的? @St.Antario:他们这样说是因为未来 CPU 可能会将其识别为某些新指令的一部分。在所有真实的 CPU 上都是如此,一旦他们使用f3 xx 建立编码,他们就会记录它是如何在旧 CPU 上运行的。 在实践中,现有 CPU 会忽略不适用于指令的前缀(除了锁定)。 据记载,rep movbe 会导致 #UD,因此rep 不会总是被忽略。即使它不适用于在REP/REPE/REPZ/REPNE/REPNZ 手册条目中指定的意义上的指令。 @St.Antario:有趣!不过,一般来说,对于较旧的指令,不适用的前缀会被忽略。在引入新指令时,如果他们愿意,可以添加更严格的规则。 IDK 为什么他们会为这种特定情况选择它。

以上是关于"rep; nop;" 是啥意思?在 x86 程序集中是啥意思?它与“暂停”指令相同吗?的主要内容,如果未能解决你的问题,请参考以下文章

2020 "第五空间"智能安全大赛 Re nop

the hash for the file is not present in the specified catalog file,是啥意

请问replace(/ \ - / g, "\ /")这个中间的正则表达式是啥意思?

利用C语言,模拟流水线,结构冒险 和 数据冒险,并采用 nop指令方式解决其冒险

dplyr 句号字符“。”是啥意思?参考?

CIL nop 操作码的目的是啥?