【问题标题】:How does asm("nop"); works?asm("nop"); 怎么样?作品?
【发布时间】:2014-06-23 06:27:23
【问题描述】:

我从http://en.wikipedia.org/wiki/NOP 中重新定义了定义,但我仍然需要一个更简单的定义。

我偶然发现了一段代码,但我不知道它到底是做什么的:

switch (Something)
    {

        case this_one:
            asm ("nop");
            break;
        case other_one:
            asm ("nop");
            break;
        default:
            asm ("nop");
            break;
    }

【问题讨论】:

  • asm 插入内联汇编,nop 是一个什么都不做的指令。代码示例没有任何用处。你对哪一部分有困难?
  • 您的代码在技术上“什么都不做”,如果不将其与其他代码位放在上下文中,就很难说出它为什么存在。但是,它可能被用于优化目的——例如保持内存对齐。当内存“对齐”为 2 个块大小的幂时,某些处理器的性能会更好。
  • 形而上学没有“无”这样的东西。 NOP 或无操作意味着 CPU(最终)会浪费时钟周期。它至少必须对操作进行解码并注意到它必须获取一条新指令。上下文中的 Nothing 表示“程序计数器”寄存器已更改; 可能没有其他副作用发生。
  • @AlexandruCimpanu 有几个目的,下面的答案中提到了一些。还有一个没有提到的是在连续指令之间插入延迟 > epsilon(如果代码与硬件一起使用,可能需要)
  • 我个人经常使用 asm NOP 来调试代码,当代码中有一个地方我想放置一个断点时。

标签: c assembly


【解决方案1】:

nop 是一条什么都不做的汇编指令——几乎什么也不做,但仍然执行机器指令,这意味着(可能)流逝的时间非常短(它的价值可能有限)在某些实时应用中。

在这种情况下,语句asm("nop"); 对程序没有语义差异。我认为它可能存在的唯一原因是“强制”编译器不折叠代码路径,如果您查看目标代码或反汇编机器代码或查看它,则使 switch 语句的机器结构可见一个调试器。

【讨论】:

  • 代码中有asm("nop");和只留下break有什么区别?
  • @AlexandruCimpanu:编译器(很可能)不会优化 asm() 指令,因为他不查看它的参数。一个简单的中断可以被优化掉。
  • @PMF:我认为你不需要nop。一个空的 volatile asm("",,,"memory") 语句应该可以解决问题。
  • @DwayneTowell:nops 在代码生成中也很有用,可以提供对齐(例如跳转目标和函数入口点)。您还可以使用 nop 为调试留出空间——您可以将跳转插入到 nop 块中并热修复您的代码...
  • @PMF:好吧,nop 产生一条指令,空的 asm 语句没有产生...
【解决方案2】:

由于没有人提到它,nop 在临界区期间也可以用来“让步”,即允许其他中断发生,以减少临界区引起的中断延迟。

这在没有操作系统的嵌入式应用程序中通常很有用,在这些应用程序中,您经常需要在关键部分轮询变量和/或状态寄存器。

在许多 RISC 处理器(ARM、AVR)上,紧跟在中断取消屏蔽之后的指令仍将被屏蔽,因此如果您只是将 sei/cli 放在一起,您将不会允许任何中断发生。

seicli 之间添加的每个nop 允许在临界区恢复之前再发生一次中断。

【讨论】:

    【解决方案3】:

    NOP 对调试很有用。即使什么都不做,因为意味着“无操作”,NOP 是关于您可以在调试器中设置断点的说明。我相信程序员想以这种方式学习“某事”的价值。这看起来很愚蠢,但一位经验丰富的程序员花了几个小时才找出原因

    if(Something);
    {
     ...
    }
    

    总是在范围内而不取决于Something 的值。我怀疑现在有人对 switch() 有类似的问题。如果程序员省略了NOP,编译器可能更容易删除整个switch() 语句。我还使用__asm__("#start");Maximum speed from IOS/iPad/iPhone 中的某些代码设置清晰的边界,但__asm__("nop"); 也会这样做。

    也如前所述,它可用于实时应用程序。例如http://www.rickard.gunee.com/projects/video/pic/tetris.php 可能会使用这个。

    【讨论】:

    • 嗯...经验丰富的程序员会启用所有编译器警告。此外,经验丰富的 C 程序员会针对那些杂散的分号开发出某种潜意识反射,并立即发现它们。
    • 这个案例是真实的,但很多年前。也许GCC没有给出警告,我不记得了。此外,人们只是有时会感到疲倦等等。
    • 感谢您发布此消息!我发现这个答案非常有帮助,因为我以前从未想过以这种方式使用 NOP。
    【解决方案4】:

    如前所述,它已在嵌入式世界中使用。有时你需要等待一两个周期,才能真正将一个引脚设置为某个状态,尤其是在一些传感器上等等......在旧石器时代的 6581 cpu 中,使用 nop 来产生延迟,因为时钟大约0.7mhz...关于中断的说法也是如此。

    【讨论】:

      【解决方案5】:

      NOP 是一条汇编指令,正如它所说的(无操作)它只是不做任何事情,但它像任何其他指令一样由 CPU 处理。 所以这意味着它将从内存中读取,将增加指令指针,但在指令解码后的执行阶段不会做任何其他事情。 饼干经常在反向工程中使用它,但不知道它还有其他用途。 我认为在 C 编程中不需要使用 NOP 指令。

      【讨论】:

      • 如果您正在运行紧密的轮询循环并且不希望编译器优化空循环,这可能会很有用。
      • @BretD 不幸的是,仅在非常简单的 uC 上才是正确的。流水线的只是跳过 nops 并且不能保证任何延迟。 - 例如 ARM,它们可用于填充。
      【解决方案6】:

      至少在 Intel x86 上,nop 是 xchg eax,eax 的助记符,因此它会与自己交换 eax 寄存器。 还有其他形式可以做同样的事情但占用更多空间(例如lea esi,[esi + eiz] - 将 0 添加到 esi),但这些不是“官方”nop 指令。

      【讨论】:

        【解决方案7】:

        nop 是一条不执行任何操作的计算机指令。在这种特殊情况下,它可能是为了防止开关被优化掉。这充其量是特定于编译器的实现,因为没有什么可以阻止它解析和优化 asm 语句。

        为什么要这样做?它可能是为了以某种方式测试机器代码的生成。在功能上,它没有用。

        【讨论】:

        • 实际上,我不认为我见过敢于优化 NOP 的编译器,因为它总是存在是有原因的。例如,在与数字逻辑电子设备交互的快速 MCU 上运行的程序可以使用 NOP 作为微型延迟,以使逻辑电平变得稳定。
        • nop 的成本很高,它在实时函数中很有用。
        • 也许吧。无论如何,它都是特定于实现的。如果 nops 甚至没有被放入 PIQ 中,我不会感到惊讶。 x86。不过,它确实占用了内存,我想这确实有一些影响。
        • 大多数编译器都不是这样。 asm 语句默认被认为是易失的(不可优化),除非您添加约束以让编译器知道内联代码的用途(使用的寄存器、内存修改等)。
        • @Lundin 不在现代 uP / uC 上仅用于填充 - 从不用于延迟 infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/…。如果您需要周期精确的延迟 - 仅屏障指令
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-03-30
        • 2013-07-08
        • 2020-06-18
        • 1970-01-01
        • 1970-01-01
        • 2012-02-10
        • 1970-01-01
        相关资源
        最近更新 更多