CIL nop 操作码的用途是什么?

发布于 2024-07-08 01:49:29 字数 355 浏览 12 评论 0原文

我正在浏览 MSIL 并注意到有很多 nop 指令。

MSDN 文章称,如果操作码被修补,它们不会采取任何行动,而是用于填充空间。 它们在调试版本中的使用比发布版本中的使用要多得多。

我知道汇编语言中使用此类语句来对齐后面的指令,但是为什么 MSIL 中需要 MSIL nops?

(编者注:接受的答案是关于机器代码 NOP,而不是问题最初询问的 MSIL/CIL NOP。)

I'm going through MSIL and noticing there are a lot of nop instructions in the MSIL.

The MSDN article says they take no action and are used to fill space if the opcode is patched. They're used a lot more in debug builds than release builds.

I know that these kinds of statements are used in assembly languages to align later instructions, but why are MSIL nops needed in MSIL?

(Editor's note: the accepted answer is about machine-code NOPs, not MSIL/CIL NOPs which the question originally asked about.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

长伴 2024-07-15 01:49:30

NOP 有多种用途:

  • 它们允许调试器在一行上放置断点,即使它与生成的代码中的其他断点组合在一起。
  • 它允许加载器使用不同大小的目标偏移量来修补跳转。
  • 它允许代码块在特定边界对齐,这有利于缓存。
  • 它允许增量链接通过调用新部分来覆盖代码块,而不必担心整体函数大小的变化。

NOPs serve several purposes:

  • They allow the debugger to place a breakpoint on a line even if it is combined with others in the generated code.
  • It allows the loader to patch a jump with a different-sized target offset.
  • It allows a block of code to be aligned at a particular boundary, which can be good for caching.
  • It allows for incremental linking to overwrite chunks of code with a call to a new section without having to worry about the overall function changing size.
静谧幽蓝 2024-07-15 01:49:30

以下是MSIL / CIL nops(不是x86机器代码nop) 用于调试:

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

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

C# 还在调用指令之后放置 Nops,以便源中的返回站点位置是调用而不是调用后的行。

Here's how MSIL / CIL nops (not x86 machine code nop) are used by debugging:

Nops are used by language compilers (C#, VB, etc.) to define implicit sequence points. These tell the JIT compiler where to ensure machine instructions can be mapped back to IL instructions.

Rick Byer's blog entry on DebuggingModes.IgnoreSymbolStoreSequencePoints, explains a few of the details.

C# also places Nops after call instructions so that the return site location in source is the call out rather than the line after the call.

草莓味的萝莉 2024-07-15 01:49:30

它为代码中基于行的标记(例如断点)提供了机会,而发布版本不会发出任何标记。

It provides an opportunity for line-based markers (e.g. breakpoints) in the code where a release build would emit none.

请你别敷衍 2024-07-15 01:49:30

老兄! 无操作太棒了! 这是一条除了消耗时间之外什么也不做的指令。 在昏暗的黑暗时代,您可以使用它对关键循环中的时序进行微调,或更重要的是作为自修改代码的填充物。

Dude! No-op is awesome! It is an instruction that does nothing but consume time. In the dim dark ages you would use it to do microadjustments in timing in critical loops or more importantly as a filler in self-modifying code.

十级心震 2024-07-15 01:49:30

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

处理器长期以来采用多个大致并行工作的管道,因此可以同时执行两条独立的指令。 在具有两个管道的简单处理器上,第一个管道可能支持所有指令,而第二个管道仅支持一个子集。 此外,当必须等待上一条尚未完成的指令的结果时,管道之间会出现一些停顿。

在这些情况下,专用的 nop 可能会强制下一条指令进入特定的管道(第一条或不是第一条),并改进后续指令的配对,从而降低 nop 的成本 超过摊销。

It may also make code run faster, when optimizing for specific processors or architectures:

Processors for a long time employ multiple pipelines that work roughly in parallel, so two independent instruction can be exceuted at the same time. On a simple processor with two pipelines, the first may support all instructions, whereas the second supports only a subset. Also, there are some stalls between the pipelines when one has to wait for the result of a previous instruction that isn't finished yet.

Under these circumstances, a dedicated nop may force the next instruction into a specific pipeline (the first, or not the first), and improve the pairing of following instructions so that the cost of the nop is more than amortized.

空气里的味道 2024-07-15 01:49:30

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

加载值到寄存器(需要8个周期)
8号
添加 1 到寄存器

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

另一个用途是填充执行单元,例如必须具有一定大小(32 字节)的中断向量,因为向量 0 的地址是 0,向量 1 0x20 等等,因此编译器将 NOP 放入其中,如果需要。

In one processor I worked for recently (for four years) NOP was used to make sure the previous operation finished before the next operation was started. For instance:

load value to register (takes 8 cycles)
nop 8
add 1 to register

This made sure register had the correct value before the add operation.

Another use was to fill in execution units, such as the interrupt vectors which had to be a certain size (32 bytes) because address for vector0 was, say 0, for vector 1 0x20 and so on, so the compiler put NOPs in there if needed.

困倦 2024-07-15 01:49:30

他们可以在调试时使用它们来支持编辑并继续。 它为调试器提供了用新代码替换旧代码而无需更改偏移量等的空间。

They could be using them to support edit-and-continue while debugging. It provides the debugger with room to work to replace the old code with new without changing offsets, etc.

十年九夏 2024-07-15 01:49:30

虽然晚了 50 年,但是嘿。

如果您手动输入汇编代码,则 Nop 非常有用。
如果您必须删除代码,您可以 nop 旧的操作码。

类似地,您可以通过覆盖某些操作码来插入新代码并跳转到其他地方。 您可以在此处放置覆盖的操作码,然后插入新代码。 准备好后,你跳回来。

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

如今,有了编译器,这些技术就不再有意义了。

50 years too late but hey.

Nop's are useful if you are typing assembly code by hand.
If you had to remove code, you could nop the old opcodes.

similary, you could insert new code by overwriting some opcode and jump somewhere else. There you put the overwritten opcodes, and insert your new code. When ready you jump back.

Sometimes you had to use the tools which were available. In some cases this was just a very basic machinecode editor.

Nowadays with compilers the techniques make no sense whatsoever anymore.

故事和酒 2024-07-15 01:49:30

它们的一个经典用途是让调试器始终能够将源代码行与 IL 指令关联起来。

One classic use for them is so that your debugger can always associate a source-code line with an IL instruction.

讽刺将军 2024-07-15 01:49:30

在软件破解场景中,解锁应用程序的经典方法是使用 NOP 修补检查密钥、注册或时间段等的行,这样它就不会执行任何操作,只是继续启动应用程序,就好像它已注册一样。

In the software cracking scene, a classic method to unlock an application would be to patch with a NOP the line that checks for the key or registration or time period or whatnot so it would do nothing and simply continue starting the application as if it is registered.

浪菊怪哟 2024-07-15 01:49:30

我还看到代码中的 NOP 会修改自身以混淆它作为占位符的作用(非常旧的复制保护)。

I've also seen NOPs in code that modifies itself to obfuscate what it does as a placeholder (veeery old copy protection).

メ斷腸人バ 2024-07-15 01:49:30

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

As ddaa said, nops let you account for variance in the stack, so that when you overwrite the return address it jumps to the nop sled (a lot of nops in a row) and then hits the executable code correctly, rather than jumping to some byte in the instruction that isn't the beginning.

酒几许 2024-07-15 01:49:30

有点非正统的用法是 NOP-Slides,用于缓冲区溢出漏洞利用。

A somewhat unorthodox use are NOP-Slides, used in buffer overflow exploits.

梦明 2024-07-15 01:49:30

它们允许链接器用较短的指令(通常是长跳转)替换较长的指令(通常是长跳转)。 NOP 占用了额外的空间 - 代码无法移动,因为它会阻止其他跳转工作。 这发生在链接时,因此编译器无法知道长跳转还是短跳转是否合适。

至少,这是它们的传统用途之一。

They allow the linker to replace a longer instruction (typically long jump) with a shorter one (short jump). The NOP takes the extra space - the code could not be moved around as it would stop other jumps from working. This happens at link-time, so the compiler can't know whether a long or short jump would be appropriate.

At least, that's one of their traditional uses.

女中豪杰 2024-07-15 01:49:30

这不是您具体问题的答案,但在过去,您可以使用 NOP 来填充 分支延迟槽,如果你无法用其他有用的指令来填充它。

This is not an answer to your specific question, but back in the old days you could use a NOP to fill a branch delay slot, if you couldn't manage to fill it with an otherwise-useful instruction.

暮光沉寂 2024-07-15 01:49:30

.NET 编译器是否对齐 MSIL 输出? 我想它可能对加速对 IL 的访问很有用...另外,我的理解是它被设计为可移植的,并且在其他一些硬件平台上需要对齐访问。

Do the .NET compilers align the MSIL output? I'd imagine it might be useful for speeding up access to the IL... Also, my understanding is that it's designed to be portable and aligned accesses are required on some other hardware platforms.

智商已欠费 2024-07-15 01:49:30

我学到的第一个汇编是SPARC,所以我熟悉分支延迟槽,如果你不能用其他指令填充它,通常是你要放在分支指令上方的指令或在循环中增加计数器,你可以使用一个NOP。

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

The first assembly I learned was SPARC so I'm familiar with the branch delay slot, if you can't fill it with another instruction, usually the instruction you were going to put above the branch instruction or increment a counter in loops, you use a NOP.

I'm not familiar with cracking, but I think is common to overwrite the stack using NOP so you have not to exactly calculate where your malicious function begins.

痕至 2024-07-15 01:49:30

我使用 NOP 自动调整进入 ISR 后累积的延迟。 非常方便地准确确定时间。

I used NOPs to automagically adjust the latency accumulated after entering an ISR. Very handy to nail timing dead on.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文