2016-10-12 6 views
0

私は一例でアセンブリ言語を習得しようとしている、または-Sオプションを使用してGCC、インテルの構文を使用して簡単なCファイルをコンパイルし、CFIが無効に呼び出していますが、(他のすべての自由な方法が非常に混乱してGCCは、コンパイル済みのアセンブリ

マイC ?ファイルは、文字通りint main() {return 0;}ですが、GCCは、この吐く:

.file "simpleCTest.c" 
    .intel_syntax noprefix 
    .def ___main; .scl 2; .type 32; .endef 
    .text 
    .globl _main 
    .def _main; .scl 2; .type 32; .endef 
_main: 
    push ebp 
    mov ebp, esp 
    and esp, -16 
    call ___main 
    mov eax, 0 
    leave 
    ret 
    .ident "GCC: (GNU) 5.3.0" 

私の本当の問題は、なぜ主な機能は、任意のプロセッサ命令(push edpmov edp, esp、など)を持っているんですが、これらは必要さえあります(私はそれは次のようになり推測プログラムを準備/シャットダウンするためのデータ管理の方法ですが、わかりません)なぜ? main関数のあとにretステートメントを発行してもかまいませんか?また、なぜ2つの主な機能(_main & ___main)がありますか?

これを要約すると、なぜこのようなものではないのですか?

.def _main 
_main: 
mov eax, 0 ;(for return integer) 
ret 
+2

( '-O2')で最適化を有効にします。 'main'は特別なことに注意してください。' int foo(){return 0;} 'を実行する方が良いかもしれません。また、コンパイラ生成コードを理解しようとすることは必ずしも容易ではありません。 – Jester

+1

あなたはWindowsのようですか?その理由は、 '___ main'が呼び出されるのは、登録された静的コンストラクタを呼び出すためです。 'とesp、-16'は' ___ main'を呼び出す前にスタックが16バイト整列していることを確認することです。 esp/ebp/leaveは、スタックフレーム用の標準的なボイラープレートコードです。デバッガで使用したときにスタックの巻き戻しデータがなくても便利ですが、必須ではありません。 –

+0

[x86タグwiki](http://stackoverflow.com/tags/x86/info)に興味深いリンクがいくつかあります。 –

答えて

0

GCCは、あなたが実際にあなたの主な機能は、別の関数を呼び出すなど、奇妙なことに、いくつかのことを行う持っていた場合、これはおそらく、少し明確になり、この

を出してくれる。

あなたのコンパイル済みコードは、最初のオペコード、mov ebp、espでスタック変数を参照するためのフレームを設定しています。これは、たとえばebpと定数で参照できる変数がある場合に使用されます。次に、スタックをAND命令で16バイトの倍数に整列します。つまり、[esp]が16の倍数に整列するように、指定されたスタックの0〜15バイトを使用しないことを意味していますバイト。これは、使用中の呼び出し規約のために重要です。

最後のopcode leaveは、バックアップされた基本ポインタをスタックポインタの現在の状態にコピーし、元の基本ポインタをpopで復元します。

私の本当の問題は、主な機能は、任意のプロセッサ命令

それはあなたがやっていないもののためのものを設定しています(それ自明でないプログラムが行うだろう)を持っていない理由である、となっていませんできるだけ最適化された "return 0"プログラムです。ほとんどの場合、元のスタックポインタのバックアップであるベースポインタを持つことで、プログラムはローカル変数にオフセットとベースポインタを自由に参照できます(引数カウントのような暗黙のもの、引数リストへのポインター、および環境へのポインター)、16の倍数のスタックポインターを持つことにより、呼び出し元の標準に従って関数を呼び出すことができます。

+0

まだ、プログラムには2つのメインがありますか? – user2624583

関連する問題