2016-10-20 3 views
1

アセンブリとプログラミングの基本を理解しています。gccのバージョンが異なる単純なCプログラムのアセンブリコードが異なるのはなぜですか?

Iは

#include <stdio.h> 

int main() 
{ 
    int a; 
    int b; 
    a = 10; 
    b = 88 

    return 0; 
} 

、次のコマンドでコンパイル、Cで簡単なプログラム次のコンパイル

GCC -ggdb -fno-スタックプロテクタtest.cの-o試験

逆アセンブルコードgccバージョン4.4.7の上記プログラムの場合:

5      push %ebp 
89 e5     mov %esp,%ebp 
83 ec 10    sub $0x10,%esp 
c7 45 f8 0a 00 00 00 movl $0xa,-0x8(%ebp) 
c7 45 fc 58 00 00 00 movl $0x58,-0x4(%ebp) 
b8 00 00 00 00   mov $0x0,%eax 
c9      leave 
c3      ret 
90      nop 

ただし、 GCCバージョン4.3.3の同じプログラムのためのmbledコードは:

8d 4c 23 04  lea  0x4(%esp), %ecx 
83 e4 f0  and  $0xfffffff0, %esp 
55    push -0x4(%ecx) 
89 e5   mov  %esp,%ebp 
51    push  %ecx 
83 ec 10  sub  $0x10,%esp 
c7 45 f4 0a 00 00 00 00 movl $0xa, -0xc(%ebp) 
c7 45 f8 58 00 00 00 00 movl $0x58, -0x8(%ebp) 
b8 00 00 00 00   mov $0x0, %eax 
83 c4 10    add $0x10,%esp 
59      pop %ecx 
5d      pop %ebp 
8d 61 fc    lea -0x4(%ecx),%esp 
c3      ret 

なぜアセンブリコードに違いがありますか?
2番目の組み立てられたコードで分かるように、なぜ%ecxをスタックにプッシュするのですか?
and $0xfffffff0, %espの意義は何ですか?

注:OSは

+6

なぜ違いはありませんか? –

+0

2番目のコードは、デバッグバージョン – Asesh

+0

@EugeneShのように見えます。質問の背後にある理由は、同じコードが同じコンパイラ出力を生成しなければならないからです。したがって、これらの実行可能ファイルはまったく同じコードから生成されたものと同じです。オブジェクトファイルがリンクされているライブラリが異なる可能性があるので、実行ファイル_は同じではないかもしれませんが、アセンブリはCから機械語への直接変換でなければなりません。 – ForceBru

答えて

6

コンパイラは、同じソースコードの同じアセンブリコードを生成するために必要とされていない同じです。 C標準では、の観測可能な動作が同じである限り、コンパイラはコードを最適化して最適化することができます。したがって、異なるコンパイラが異なるアセンブリコードを生成することがあります。あなたのコードの場合

-O3GCC 6.2だけ生成します。

xor  eax, eax 
ret 

あなたのコードは、本質的に何もしませんので。したがって、単純なreturn文になります。

+0

あなたは間違いないが、コンパイラがそのようなコードを生成する理由は疑問だと私は思う。 OPはアセンブラコードを読むことができるので、コンパイラが同じ入力プログラムに対して異なるコードを生成することがあることも知っていると思います。 (注:私はあなたにdownvoteをしなかった) – jforberg

+4

@jforberg "私は質問がなぜコンパイラがそのようなコードを生成するのだろうと思う" - 私の答えは*できるように/許可されています*。私はOPが知っていることをOPが知っているのを知っています。なぜなら、OPがその知識を既に持っていれば、この質問は賞賛されないからです。 – usr

+0

私は常にOPに疑問の恩恵を与えるべきだと思います。特にSOの回答はOPの利益のためだけではないからです。 GCCが2番目の例でコードを生成する理由は個人的にはわかりませんが、私は知りたいと思っています。このスレッドの誰もその質問に答えるつもりはありません。私は悲しいと思います。私は同じ日に2回あなたと戦いたくないから今はやめます。こんばんは。 – jforberg

0

はあなたに特定のタスクのための有効なコードを作成するために存在する多くの方法いくつかのアイデアを与えるために、私はこの例では、役立つかもしれないと思いました。

時々あなたがすべてでこのレベルで手書きのアセンブリに対するコンパイラと競合することはできませんとサイズは、明らかにアセンブリのプログラマをターゲット、競技をコーディングがあります。

競合タスクが(単一バイトまたはピクセル完成まで)正確な入力および出力仕様と、エントリレベルと総努力が妥当するためにかなり自明です。

だから目標として、単一の単純なルール「最小サイズ」とほぼ些細な正確な作業、人間生成されたコードを(現時点ではまだ簡単な仕事のためのコンパイラを上回る)、持っています。

あなたのロジックでは、すべての競技者が同じ結果を生み出すことが絶対に明らかです。

これに現実世界の答えは、例えばある:

Hugi Size Coding Competition Series - Compo29 - ランダム迷路ビルダー

12エントリ(バイト単位)コードのサイズ:122、122、128、135、136、 137,147、... 278(!)。

私は最初の2つのエントリーを賭けました。どちらも122Bの方がおそらく十分に異なっています(実際にチェックするにはあまりにも怠惰です)。

高水準プログラミング言語とマシン(コンパイラ)から有効なマシンコードを生成することは、もっと複雑な作業です。コンパイラは推論で人間と競合することはできませんが、「C++コンパイラによってどのように良いコードが生成されるか」の大部分は、C++言語自体がマシンコード(コンパイルが容易)に近く定義されていることや、特定のコードパスに対して何千もの変種を扱い、ほとんど最適な解をほとんど無差別な力で探します。

オプティマイザの背後にある数値的な「推論」は、人間がまだ到達できないポイントに近づいていますが、自分のやり方に似ています。フルサイズのアプリケーションをコンパイルするための妥当な努力の中で、

この時点では、いくつかのデバッグコードがいくつかのヘルパープロローグ/エピローグ命令で異なると推論しています...最適化されたコードに違いがあり、その違いが人間にとって「明白」であっても、コンパイラは、タスクのコンテキストを真に理解することなく、特定のコードに対して普遍的なルールを適用する必要があるので、少なくともそれを生成することができます。

関連する問題