2011-01-14 10 views
2

私はちょうどCでコードサンプルを書いて、それを逆アセンブルしようとしました。コードサンプルは次のとおりです。gcc stack optimization?

void start() { 
    char phone[100]; 
    strcmp(phone, "12312312313"); 

    char name[100]; 
    strcmp(name, "eQuiNoX"); 

    char contact[100]; 
    strcmp(contact, "PM twitter.com/eQuiNoX__"); 
} 

私はスタート機能を分解するとき、私は以下の取得: -

08048414 <start>: 
8048414: 55     push ebp 
8048415: 89 e5     mov ebp,esp 
8048417: 81 ec 58 01 00 00  sub esp,0x158 
804841d: c9     leave 
804841e: c3     ret 
  1. 私は最適化のいずれかの種類を有効にしていません。誰かが、スタックに値をプッシュしてstrcmpメソッドを呼び出すアセンブリコードではなく、158をespから差し引いた理由を説明できますか?ユーザー入力に依存しないからですか?
  2. また、extended assemblyを生成する方法はありますか(正しいことがわからない場合、スタックに値をプッシュするアセンブリコードとstrcmp関数の呼び出しを見たいだけです)。私はそれを行うことができる方法はありますか?
  3. プロセッサアーキテクチャまたはgccのバージョンに特有のこの種の動作ですか?
+0

この最適化では、この種の惨事は理にかなっていますが、最適化が行われていないと奇妙に見えます。あなたは最適化がないのですか? – BlackBear

+0

とにかく、strcmp()の結果を使用して、それらの配列を初期化してください。 – BlackBear

+0

明示的に-O0を渡しましたか? -fno-builtinを渡しましたか? – Joshua

答えて

10

まず、strcmpは標準ライブラリ関数なので、gccはどのように動作するかについて特別な知識は自由です。実際にはそうです。ライブラリコールを生成することはめったにありません。無効にするには​​を試すことができます。

次に、単位化された値と比較しています。これは未定義の行動だと私は信じています。したがって、コンパイラはランダムなコードを生成することを含め、それが気に入っている何かを行うことができます。

-Sオプションをgccに試すと、より詳細な逆アセンブリ(またはアセンブリの欠如)を得ることができます。あるいは、-g(デバッグ)でコンパイルすると、objdump -Sはアセンブルされたコードと共にソースを表示します。ここで

は私がgcc -fno-builtin -g -O0 test.c -cしてコンパイルし、その後objdump -S test.oとダンプの例です:

test.o:  file format elf64-x86-64 


Disassembly of section .text: 

0000000000000000 <main>: 
#include <string.h> 

int main() { 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: 48 83 ec 10    sub $0x10,%rsp 
    const char foo[] = "foo"; 
    8: 8b 05 00 00 00 00  mov 0x0(%rip),%eax  # e <main+0xe> 
    e: 89 45 f0    mov %eax,-0x10(%rbp) 
    return strcmp(foo, "bar"); 
    11: 48 8d 45 f0    lea -0x10(%rbp),%rax 
    15: be 00 00 00 00   mov $0x0,%esi 
    1a: 48 89 c7    mov %rax,%rdi 
    1d: e8 00 00 00 00   callq 22 <main+0x22> 
} 
    22: c9      leaveq 
    23: c3      retq 
+0

MinGW 4.5.1のテストでは、 '-fno-builtin -O0'はgccに' strcmp() 'を強制的に呼び出さないようです。なぜ私は不思議です。 –

+0

@Michael Burr:確かに、デッドコード除去オプションを明示的にオフにしてみることもできます。 string.hがstrcmpに対して面白いことをする可能性もありますので、-E出力を確認してみてください。 – derobert

+0

-E出力で 'strcmp()'(呼び出し以外)を見るのは 'int __attribute __((__ cdecl__))__attribute__((__nothrow__))strcmp(const char *、const char *)__attribute__ (__pure __))); '。とにかく、これはちょうどアイドルな好奇心でした。確かに、このサイクルに何のサイクルも費やす必要はありません。 –

0

それが本当に最適化したようです。最適化が行われていないことを確認するために、-O0フラグを付けてコンパイルを試みることができます(ただし、動作するかどうかはわかりません)。コピー伴うsub esp,0x158命令について

int start() { 
    char phone[] = "43423432"; 
    return strcmp(phone, "12312312313"); 
} 
4

、というよりもpush操作の最大積載量を生成する(:

それとも、ただ、あなたが実際にそれらを使用するコンパイラを表示するために開始関数からのCMPの結果を返すことができますオペランドもスペースを確保するだけでなくスタックにも渡します)、通常、コンパイラはスタックポインタを1回だけ移動することによって、すべてのローカル変数に十分な領域を確保します。それがこの指導がやっていることです。 0x158は10進数で344なので、配列のために300バイトを予約しています。おそらく、コンパイラが生成した構造体のために余分なスペースが必要です(またはスタックにstrcmpオペランドを置くこともできます)。

-2

gccはデフォルトで-O2を使用します。したがって、さらに最適化を有効にしていなくても、-O2が使用されます。 -O0を使用してすべての最適化をオフにします。

sub esp,0x158は、3つのアレイ(合計303バイト)を定義して予約したスタックメモリを解放するために344を減算します。おそらく他のものもあります。

+3

これは当てはまりません、gccはデフォルトで-O0を使用します。 http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html – gravitron

+0

本当ですか? Intel iccコンパイルはデフォルトで-O2を使用します。私はiccをたくさん使いました。これが私がこのミスをした理由です。 – Elalfer

4
  1. コードがプログラムの実行に影響を与えないためです。戻り値が破棄される関数呼び出しでは、すべての変数が使用されるため、コンパイラは未使用コードとしてタグ付けし、削除する必要があると感じました。使用しないコードを保存したい場合は、-O0でコンパイルして、最適化を行わないようにしてください。

  2. 上記を参照してください。

  3. 私はほとんどのコンパイラがアーキテクチャとは無関係にこの最適化を実行すると思っています。

+0

「純粋」であることが知られている関数に対してのみ実行できます。 – ruslik

+0

@ruslik:提示された関数の場合と同じです。それにもかかわらず、それは正しい用語です。 – jweyrich