2012-02-09 19 views
0

私はasmで多くを扱い、GDBでレジスタとメモリを調べているCの本を読んでいます。 問題は、まったく同じソースをコンパイルして逆アセンブルすると(実際には本のCDに含まれているソースファイルを使用して)、アセンブリの説明は本の内容とかなり異なって見えます。 本書では、Intel Flavoredアセンブリを使用しており、gdbに "set disassembly intel"を置いていますので、そうではありません。命令は異なる順序で、いくつかはすべて一緒に異なっており、いくつかの違いがあります。例えばgdbの奇妙な結果

は、本の中でMOV命令は、EIPレジスタにある:変数iが0の初期化に対応

(gdb) x/i $eip 
mov DWORD PTR[ebp-4], 0x0 

、forループで(I = 0、I < 10、I ++

(gdb) x/i $eip 
mov DWORD PTR[esp+0x1c], 0x0 

予告それは別のレジスを参照しています:私はこれを参照してください)実行;)

しかし、同じ場所にブレークポイントと私のGDBコンソール、中(メインを破る設定すべて一緒に - espの代わりにebp 私はespの値をチェックすると、それは0x1c自体です。しかし、0x1cやesp + 0x1cにあるものを調べると、私はそれらのアドレスを見ることができないことがわかります

この本の説明にあるように、 ebp、ebp-4などのトレイルに続き、ebpレジスタで何も起こっていないようです。

この本は2008年に書かれたので、私はできませんgccやgdbのバージョンを変更すると、その変更の重要な部分が導入されることになってしまいます(あるいはやりましたか?)可能性があります。コンパイラの最適化や、 ?

ありがとうございます。

編集:Strange。私はそれぞれの提案を試みたが、何も働かなかった。それから、私はrm a.outを実行して新しく再コンパイルしましたが、今は正常に動作します(指示は本とは異なりますが、本のアドレスに対応するアドレスを調べることができます。正確に同じasmである必要はありません、それはちょうどそれも簡単になります!) あなたのすべての助けと提案をもう一度感謝します。

答えて

0

これはすべてプラットフォームとコンパイラ固有のものです。あなたができることはあまりありません。

+0

ありがとうございました。本はgccでコンパイルする(私はバージョンを確認し、qeustionを更新する必要があります)、Linuxを実行している私は32ビットのIntelを使用しています。この本はUbuntuをベースにしています(バージョンを確認する必要があります)。最新のArchをインストールしています。 私は同じアーキテクチャと同じコンパイラ(gcc)でマシンコードが同じではないと思いますか? どちらの方法でも、値が私が調べることのできないアドレスに初期化されていることがわかり、$ esp(つまりスタックポインタ)によって参照されているということも変わってしまいます。 – speakingcode

+1

いいえ、理由は同じではありません。 '-O0'や' -march = i386'で遊ぶことができます。しかし、それが全く違うことは驚くべきことではありません。 –

1

これを引き起こす原因は何百万もあります。別のアーキテクチャーでコードをコンパイルした場合は、これを期待しています(32ビットと64ビットを意味するわけでもありません)。言い換えれば、異なるCPUアーキテクチャーは実行順序を変えることができます。 。最適化を使用してプログラムをコンパイルすると、CPUのパイプラインを最適に活用するために実行の順序が変更されます。これは、いくつかのNOOP命令を追加すること、またはそれらを完全に再注文することを意味するかもしれない(もちろん、理由の中で)。さらに、いくつかのCPUには複数の方法がありますが、一方の方法は通常はもう一方の方法よりも高速です(Intel LOOP命令が思い浮かぶ - 現代のコンパイラはこの命令をペストのように避けるのはひどいため)。あるレジスタが他のレジスタよりも効率的であれば、それを使用します。

ストーリーのモラル:学習目的のために、作成者と読者の両方が、すべての最適化を無効にする必要があります。さらにボーナスポイントを追加するには、同じバージョンのgccと同じプラットフォームを使用します。

+0

洞察に感謝します。私が思っていることのようなものですが、どうすれば最適化を強制することはできません。正確なメモリアドレスや命令はアーキテクチャーによって異なるかもしれないことは理解していますが、これはコンパイラの要点ですが、私はちょっと驚いています。何もしていないので、メインループのforループが続く) 実際には、値は、私が調べることができない(esp + 0x1c)というアドレスで初期化されていると言われていますが、これは誤りではありません。 – speakingcode

+0

@rootlicker 'gcc -O0'(文字Oの後に数字0が続きます) –

1

コンパイルしたコードが-fomit-frame-pointersでコンパイルされていて、GCC-4.6でデフォルトになったようです。

明示的に-fno-omit-frame-pointerの建物を試してみてください。私はその結果が本のほうにずっと近いと思う。