nop操作码的目的是什么?

我正在通过MSIL,并注意到有很多nop指令。 MSDN文章说,他们不采取任何行动,并用于填补空间,如果操作码被修补。 它们在debugging版本中比在发布版本中用得更多。 我知道在汇编语言中使用这些types的语句来确保操作码符合字边界,但是为什么在MSIL中需要它?

NOP有几个目的:

  • 它们允许debugging器在一条线上放置一个断点,即使它与生成的代码中的其他位置组合在一起。
  • 它允许加载器用不同大小的目标偏移量跳转。
  • 它允许一段代码在一个特定的边界alignment,这对caching很有好处。
  • 它允许增量链接,通过调用一个新的部分来覆盖代码块,而不必担心整个函数的大小发生变化。

下面是debugging中使用nops的方法:

语言编译器(C#,VB等)使用Nops来定义隐式序列点。 这些告诉JIT编译器在哪里确保机器指令可以映射回IL指令。

Rick Byer关于DebuggingModes.IgnoreSymbolStoreSequencePoints的博客文章解释了一些细节。

C#在呼叫指令之后也放置了Nops,这样源中的返回站点位置就是呼叫而不是呼叫之后的线路。

它在代码中提供了一个基于行的标记(例如断点)的机会,在这个代码中,一个发布版本将不会发布。

好家伙! 没有操作太棒了! 这是一个只会消耗时间的指令。 在昏暗的黑暗时代,您可以使用它在关键循环中进行微调,或者更重要的是作为自我修改代码中的填充。

在针对特定处理器或体系结构进行优化时,它还可以使代码运行得更快:

处理器长期使用多个并行工作的pipe道,因此可以同时执行两条独立的指令。 在具有两个pipe道的简单处理器上,第一个可以支持所有的指令,而第二个只支持一个子集。 另外,当需要等待先前的还没有完成的指令的结果时,在stream水线之间有一些停顿。

在这种情况下,专用的nop可能会强制下一条指令进入特定的stream水线(第一条,而不是第一条),并改进以下指令的配对,以使nop的成本高于摊销。

它们的一个典型用法是让debugging器始终可以将源代码行与IL指令相关联。

他们可以在debugging时使用它们来支持编辑和继续 。 它为debugging器提供了工作空间,用新的替代旧代码而不改变偏移量等。

Nop在缓冲区溢出攻击的有效载荷中是必不可less的。

正如ddaa所说的,nops让你在堆栈中logging变化,所以当你覆盖返回地址时,它会跳转到nop sled(连续很多的nop),然后正确地命中可执行代码,而不是跳到某些在不是开始的指令中的字节。

50年太晚了,但嘿。

如果您正在手工input汇编代码,则Nop非常有用。 如果您必须删除代码,则可以禁用旧的操作码。

相似的,你可以通过覆盖一些操作码来插入新的代码并跳转到别的地方。 在那里你把覆盖的操作码,并插入你的新代码。 准备好后,你跳回来。

有时你必须使用可用的工具。 在某些情况下,这只是一个非常基本的机器码编辑器。

现在编译器的技术已经没有任何意义了。

在软件破解的场景中,解锁应用程序的一个经典方法是用NOP补丁来检查密钥或注册或时间段,或者什么都不做,所以它什么也不做,简单地继续启动应用程序就好像它被注册一样。

我还看到了代码中的NOP,它会修改它自己作为占位符(veeery旧版本保护)的function。

有些非正统的用法是NOP-Slides ,用于缓冲区溢出攻击。

它们允许连接器用较短的指令(短跳转)代替较长的指令(通常是跳远)。 NOP需要额外的空间 – 代码不能移动,因为它会阻止其他跳转工作。 这发生在链接的时候,所以编译器不能知道一个长或短的跳转是否合适。

至less,这是他们的传统用途之一。

这不是对你的具体问题的回答,但是回到过去,如果你不能用其他有用的指令来填充,你可以使用NOP来填补分支的延迟时间 。

.NET编译器alignmentMSIL输出吗? 我想可能是加速访问IL可能是有用的…此外,我的理解是,它的devise是可移植和alignment的访问需要在其他一些硬件平台上。

我学到的第一个程序集是SPARC,所以我对分支延迟槽很熟悉,如果你不能用另一条指令来填充它,通常是你要在分支指令之上放置的指令或者循环递增一个计数器,一个NOP。

我不熟悉破解,但我认为使用NOP覆盖堆栈很常见,所以您不必准确计算恶意函数开始的位置。

我使用NOP来自动调整进入ISR后累计的延迟。 非常方便的钉死时间。

在我最近工作的一个处理器(四年)中,NOP被用来确保之前的操作在下一个操作开始之前完成。 例如:

装载值寄存器(需要8个周期)nop 8加1寄存器

这确保寄存器在添加操作之前具有正确的值。

另一个用途是填充执行单元,例如中断向量必须是一定的大小(32字节),因为vector0的地址是0,对于向量1 0x20等等,所以编译器把NOP放在那里if需要。