82

MSIL を調べていると、MSIL に多くのnop命令があることに気付きました。

MSDN の記事によると、オペコードにパッチが適用された場合、何もアクションを起こさず、スペースを埋めるために使用されます。これらは、リリース ビルドよりもデバッグ ビルドで多く使用されます。

これらの種類のステートメントがアセンブリ言語で使用され、後の命令を調整することは知っていますが、なぜ MSIL で MSIL nops が必要なのですか?

(編集者注:受け入れられた回答は、質問が最初に尋ねたMSIL / CIL NOPではなく、マシンコードNOPに関するものです。)

4

18 に答える 18

110

NOP にはいくつかの目的があります。

  • デバッガーは、生成されたコードで他の行と組み合わされている場合でも、行にブレークポイントを配置できます。
  • これにより、ローダーは異なるサイズのターゲット オフセットでジャンプにパッチを当てることができます。
  • コードのブロックを特定の境界に揃えることができるため、キャッシュに適しています。
  • これにより、関数全体のサイズの変更を心配することなく、新しいセクションへの呼び出しでコードのチャンクを上書きするインクリメンタル リンクが可能になります。
于 2008-10-24T19:41:12.837 に答える
11

デバッグでMSIL/CIL nops(x86マシンコードではないnop)がどのように使用されるかを次に示します。

Nopsは、言語コンパイラ(C#、VBなど)が暗黙のシーケンスポイントを定義するために使用します。これらは、マシン命令をIL命令にマップして戻すことができる場所をJITコンパイラに通知します。

DebuggingModes.IgnoreSymbolStoreSequencePointsに関するRickByerのブログエントリでは、いくつかの詳細について説明しています。

また、C#は呼び出し命令の後にNopsを配置して、ソース内のリターンサイトの場所が呼び出し後の回線ではなく呼び出し元になるようにします。

于 2008-10-25T03:15:34.933 に答える
9

これにより、リリース ビルドでは何も生成されないコードで、行ベースのマーカー (ブレークポイントなど) を使用できるようになります。

于 2008-10-24T19:16:39.643 に答える
6

また、特定のプロセッサまたはアーキテクチャ向けに最適化すると、コードの実行が速くなる場合があります。

プロセッサは長い間、ほぼ並行して動作する複数のパイプラインを採用しているため、2 つの独立した命令を同時に実行できます。2 つのパイプラインを持つ単純なプロセッサでは、最初のパイプラインはすべての命令をサポートし、2 番目のパイプラインはサブセットのみをサポートします。また、まだ完了していない前の命令の結果を待たなければならない場合、パイプライン間にいくつかのストールがあります。

このような状況では、専用のnopは、次の命令を特定のパイプライン (最初のパイプライン、または最初のパイプライン以外) に強制し、後続の命令のペアリングを改善して、nopのコストを 償却以上に抑えることができます。

于 2008-10-24T22:43:13.267 に答える
6

お前!ノーオペレーションは素晴らしいです!時間を消費するだけの命令です。暗い暗黒時代には、重要なループでタイミングの微調整を行うために、またはさらに重要なことには、自己修正コードのフィラーとして使用します。

于 2008-10-24T19:19:02.977 に答える
5

私が最近 (4 年間) 働いていたあるプロセッサでは、NOP を使用して、次の操作が開始される前に前の操作が確実に終了するようにしていました。例えば:

値をレジスタにロード (8 サイクルかかります) nop 8 レジスタに 1 を追加

これにより、追加操作の前にレジスタが正しい値を持っていることが確認されました。

別の用途は、特定のサイズ (32 バイト) である必要がある割り込みベクトルなどの実行ユニットを埋めることでした。これは、ベクトル 0 のアドレスが 0、ベクトル 1 0x20 などであったため、コンパイラはそこに NOP を配置します。必要です。

于 2009-05-28T13:03:36.383 に答える
4

50年遅すぎますがねえ。

Nopは、アセンブリコードを手動で入力する場合に便利です。コードを削除する必要がある場合は、古いオペコードを削除できます。

同様に、オペコードを上書きして別の場所にジャンプすることで、新しいコードを挿入できます。そこに上書きされたオペコードを配置し、新しいコードを挿入します。準備ができたら、ジャンプして戻ります。

時々あなたは利用可能なツールを使わなければなりませんでした。場合によっては、これは非常に基本的なマシンコードエディタでした。

今日のコンパイラでは、この手法はもはや意味がありません。

于 2009-05-28T12:46:59.147 に答える
4

デバッグ中にエディット コンティニュをサポートするためにそれらを使用している可能性があります。これにより、デバッガーは、オフセットなどを変更せずに古いコードを新しいコードに置き換える作業を行うことができます。

于 2008-10-24T19:24:02.250 に答える
3

やや異例の使用法は、バッファオーバーフローのエクスプロイトで使用されるNOP-Slidesです。

于 2009-02-02T09:28:29.030 に答える
3

それらの古典的な使用法の 1 つは、デバッガーが常にソース コード行を IL 命令に関連付けることができるようにすることです。

于 2008-10-24T19:17:58.797 に答える
3

ソフトウェアクラッキングのシーンでは、アプリケーションのロックを解除するための古典的な方法は、キー、登録、期間などをチェックする行に NOP をパッチすることです。これにより、何もせず、登録されているかのようにアプリケーションを起動し続けることができます。 .

于 2008-10-24T19:33:08.330 に答える
3

ddaa が言ったように、nops を使用するとスタック内の分散を考慮できるため、戻りアドレスを上書きすると、nop スレッド (連続して多数の nop) にジャンプし、実行可能コードにジャンプするのではなく、正しくヒットします。先頭ではない命令のバイト。

于 2008-10-25T02:24:50.277 に答える
3

また、プレースホルダーとしての機能を難読化するために自分自身を変更するコード内の NOP も見てきました (非常に古いコピー保護)。

于 2008-10-24T20:03:31.873 に答える
1

私が最初に学んだアセンブリはSPARCだったので、分岐遅延スロットに精通しています。別の命令、通常は分岐命令の上に配置する命令、またはループでカウンターをインクリメントする命令で埋めることができない場合は、次を使用します。 NOP。

私はクラッキングに精通していませんが、NOPを使用してスタックを上書きするのが一般的であるため、悪意のある関数がどこから始まるかを正確に計算する必要はないと思います。

于 2008-10-24T20:55:02.597 に答える
1

NOP を使用して、ISR に入った後に蓄積されたレイテンシーを自動的に調整しました。タイミングを釘付けにするのに非常に便利です。

于 2008-10-25T04:21:08.857 に答える
1

これにより、リンカーは長い命令 (通常はロング ジャンプ) を短い命令 (ショート ジャンプ) に置き換えることができます。NOP は余分なスペースを取ります。他のジャンプが機能しなくなるため、コードを移動できませんでした。これはリンク時に発生するため、コンパイラは長いジャンプと短いジャンプのどちらが適切かを判断できません。

少なくとも、それは伝統的な用途の 1 つです。

于 2008-10-24T19:22:23.920 に答える
1

これはあなたの特定の質問に対する答えではありませんが、昔は NOP を使用して分岐遅延スロットを埋めることができましたが、そうでなければ有用な命令で埋めることができなかった場合。

于 2008-10-24T19:26:04.490 に答える
1

.NET コンパイラは MSIL 出力を調整しますか? ILへのアクセスを高速化するのに役立つかもしれないと思います...また、移植できるように設計されており、他のハードウェアプラットフォームでは整列アクセスが必要であると理解しています。

于 2008-10-24T19:27:27.797 に答える