2011-01-25 21 views
17

は、私がnopw命令のマシンコードのエンコードがどのように機能するかを理解しようとしています:http://john.freml.in/amd64-noplで「nopw」に関するいくつかの議論がありAMD64 - nopwアセンブリ命令?このコンパイラの出力で

00000000004004d0 <main>: 
    4004d0:  eb fe     jmp 4004d0 <main> 
    4004d2:  66 66 66 66 66 2e 0f nopw %cs:0x0(%rax,%rax,1) 
    4004d9:  1f 84 00 00 00 00 00 

。誰でも4004d2-4004e0の意味を説明できますか?オペコードのリストを見ると、66 ..のコードはマルチバイト展開であるようです。私はおそらく、私が数時間にわたってオペコードのリストを掘り下げようとしない限り、ここより良い答えを得ることができると感じています。


は、ASM出力は、単純な無限ループにまで最適化Cに下記(非常識)コードからのものであること:

long i = 0; 

main() { 
    recurse(); 
} 

recurse() { 
    i++; 
    recurse(); 
} 

gcc -O2でコンパイルされ、コンパイラは無限の再帰とターンを認識するそれは無限ループに入ります。それは実際にrecurse()機能を呼び出すことなくmain()でループするということは、実際には、とてもよくこれを行います。


編集者メモ:NOPを使ったパディング関数は、無限ループに特有のものではありません。ここでのNOPの長さの範囲と機能のセットは、私は、これは単なる分岐遅延命令で推測、on the Godbolt compiler explorer.

+0

ランダムなジャンクパディングを見ていますか? –

+1

おそらく!私は本当に知りません!それはすべての美しさです! WHEEE。しかし、実際には、リンクから、プロセッサが速度最適化のための1つの命令としてブロックをロードするはずですが、 'jmp'のおかげでそれは実現しません。私はちょうどそれの意味を得る。私は0x90が何であるかを知っていますが、 '66 .. ..'で何が起こっているのか、なぜ72ビット長であるのか分かりません。 –

+1

これは理由ではありませんが、あなたは[私、奇妙なNOPsがあります! - The Old New Thing](http://blogs.msdn.com/b/oldnewthing/archive/2011/01/12/10114521.aspx)を読んでください。 – ephemient

答えて

20

0x66バイトは、「オペランド・サイズオーバーライド」の接頭辞です。これらのうちの1つ以上を有することは、1つを有することに相当する。

0x2eは、64ビットモードでは「ヌルプレフィックス」です(そうでない場合はCS:セグメントオーバーライドで、アセンブリニーモニックで表示されます)。

0x0f 0x1f MODRMバイト

0x84かかりNOPための2バイトのオペコードは、5バイト以上を使用するアドレッシングモードのModRM byteこれは、この場合のコードです。

いくつかのCPUは、3つ以上のプレフィックスを含む命令をデコードするのが遅いため、SIB + disp32を指定するModRMバイトは5つのプレフィックスバイトよりも5バイト余分に使用する方がはるかに良い方法です。

AMD K8 decoders in Agner Fog's microarch pdf

命令デコーダのそれぞれは、クロック サイクルごとに3つの接頭辞を扱うことができます。これは、3つのプレフィックスそれぞれに3つの命令が同じクロック・サイクルで デコードすることができることを意味しています。復号するために余分なクロック・サイクルを要する 6プレフィックス - 4と命令。


基本的に、これらのバイトはとにかく実行されることはありません飽きないだろう一つの長いNOP命令です。コンパイラが.p2align 4ディレクティブを発行したので、次の関数が16バイトの境界に揃うようにするために、アセンブラにはNOPが埋め込まれています。gcc's default for x86 is
-falign-functions=16
。実行されるNOPの場合、long-NOPの最適な選択はマイクロアーキテクチャに依存します。 Intel SilvermontやAMD K8のような多くのプレフィックスで刻まれたマイクロアーキテクチャでは、3つの接頭辞を持つ2つのNOPがそれぞれより速く解読されるかもしれません。

ブログの記事(http://john.freml.in/amd64-nopl)にリンクされている質問では、コンパイラが1バイトの0x90 NOP命令の代わりに複雑な単一NOP命令を使用する理由が説明されています。

あなたは、AMDの技術参照文書で命令エンコーディングについての詳細を見つけることができます。

主に「AMD64アーキテクチャプログラマーズ・マニュアル第3巻:汎用およびシステム命令」に。私は、インテルのx64アーキテクチャーに関するテクニカルリファレンスが同じ情報を持つことを確信しています(さらに理解しやすいかもしれません)。

+0

ModRMバイトの意味... http://ref.x86asm.net/coder64.html#x0F1Fは、ヒントNOPに使用されているModRMバイトを以下のようにリストしています。1.米国特許第5,701,442号2. sandpileを参照してください。 org - IA-32アーキテクチャ - オペコードグループ。私はそれらをチェックしていないが、あなたが気にしている場合に備えて。 – Bahbar

+0

これはNOPなので、mod/rmバイトは何もしません。これは、デコーダが迅速にデコードできるように、さまざまな長さの命令を可能にする手段として、命令の一部です。いくつかのCPUでは多くのプレフィックスをデコードするのが遅いので、 '66'オペランドサイズのプレフィックスを5回以上繰り返すだけでは、SIB + disp32を使用するアドレッシングモードを指定するmod/rmよりもかなり悪いです。 –

1

です。

-3

私はnopwがジャンクであることを信じて - 私はあなたのプログラムの中で読んだことがないし、これをインクリメントする必要はこのようにありません。

+0

'i'は、失敗したときにスタックサイズをチェックする便利な方法を教えてくれました。私の限られた知識がある限り、Gdbは「印刷サイズのスタック」キーを持っていません。最適化レベルが上がると、コンパイラがインクリメントを取り除くのを見るのはさらに面白いです。このプログラムは意図的に「狂気」です。 –

+0

私の主張は、コンパイラがそれを最適化したことです。 –

+0

しかし、それについての質問はありません。問題のポイントは、そのように「nop」(ここでは「nopw」)が出てくる理由です。標準の 'nop'は0x90であり、ちょうど繰り返されます。使用されていない変数として 'i'を置くことは、コードに触れていなくても、意図的かつ外部的に有用でした。 –

2

アセンブラ(コンパイラではありません)は、次の境界境界まで、それが適合することがわかる最も長いNOP命令でコード化します。これはあなたが見ているものです。

関連する問題