2017-10-31 17 views
-2

私は、3つの変数を乗算して加算して結果を返す単純なcプログラムを持っています。私はコードを32ビットマシンでアセンブリ言語(ATT形式)にコンパイルしました。私はアセンブリコードを習得しようとしていますが、私はいくつかの行を理解することができますが、結果がどうなるか、なぜ実現するのかなど、leal (%edx, %edx, 2), %edxのような理由を理解する助けが必要です。Cアセンブリ言語ATTウォークスルー?

アセンブリコード

.file "calc.c" 
     .text 
.globl calc 
     .type calc, @function 
calc: 
     pushl %ebp     #prolog 
     movl %esp, %ebp    #prolog 
     movl 8(%ebp), %edx   #move %ebp +8 into %edx 
     movl 16(%ebp), %ecx   #move %ebp +16 into %ecx 
     leal (%edx,%edx,2), %edx 
     movl 12(%ebp), %eax 
     leal (%edx,%eax,2), %eax 
     movl %ecx, %edx 
     sall $4, %edx 
     subl %ecx, %edx 
     addl %edx, %eax 
     popl %ebp 
     ret 
     .size calc, .-calc 
     .ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3" 
     .section  .note.GNU-stack,"",@progbits 

Cプログラム

#include <stdio.h> 
int calc(int x, int y, int z){ 
    return 3*x + 2*y + 15*z; 
} 
int main(void) { 
    int x = 2; 
    int y = 6; 
    int z = 11; 

    int result = calc(x,y,z); 

    printf("x=%d, y=%d, z=%d, result=%d\n", x,y,z,result); 
    return 0; 
} 

誰かが私はプロローグから始まる問題を追跡に役立つ可能性があります。

+3

あなたはマニュアルを読んでみましたか?マニュアルが 'lea'命令について何を言っていますか? '(a、b、c)'オペランド表記については何と言いますか? – fuz

+3

コンパイラに最適化を指示します。最適化されていないコンパイラで生成されたアセンブリを読み込むのは苦痛です。 – EOF

+2

[LEA命令の目的は何?]も参照してください(https://stackoverflow.com/questions/1658294/whats-the-purpose-of-the-lea-instruction) – Jester

答えて

1

:お使いのシステムは、アセンブラのゲームとは逆の順序

8(%ebp) = x = edx 
12(%ebp) = y = eax 
16(%ebp) = z = ecx 

で引数を推進している場合パラメータx。それは3で乗算されるので、アセンブリコードで容易に認識可能である:

movl 8(%ebp), %edx 

....

leal (%edx,%edx,2), %edx 
movl 12(%ebp), %eax 
leal (%edx,%eax,2), %eax 

それはEDXに引数xの値を移動させます。スタックフレーム内の引数xのアドレスはebp + 8です。その後、lealを使用してedxを2 * edxに追加し、その値をedxに格納します。それは3 * xに等しい。
引数yをeaxにロードします。これは、yが32ビットのintであるため、xの開始アドレスから4バイト先にあるため、簡単に認識できます。
次レアルは、このようにEAXにあなたは3 * X + 2 * yを有し、2 * EAX(すなわち、2 * Y)とEDX(すなわち、3 * X)を追加し、EAXに結果を格納します。
等が...

+0

これは、私がやろうとしていたことよりもはるかに意味があります: '0x8 + 0x8 * 2 =%edx address'。 –

-1

あなたのコードを最適化しないことから始めることをお勧めします。オプティマイザがゲームをしています。

int calc(int x, int y, int z){ 
    return 3*x + 2*y + 15*z; 
} 

ルックで:たぶん、それは最高の心の中でCの関数コードを説明することができ

(%edx,%edx,2) = edx + 2 x edx = 3 x edx (3 x X) 
(%edx,%eax,2) = edx + 2 x eax = (3 x X + 2 * y) 

    movl %ecx, %edx 
    sall $4, %edx = (16 x Z) 
    subl %ecx, %edx = 15 x Z 
+2

でコンパイルされたコードでコードを置き換えることができます。これは' gcc -O0'出力です。デバッガを使ってC変数を変更することをサポートするためには、すべてのC文の間でspill/reloadを使い、gdbの 'jump'コマンドを使用します。 'lea' *はx86では3倍になります。コードサイズを最適化すると 'imul $ 3、(mem)、%eax'できますが、gccは' -O0'でそれをしないように選択し、小さな定数で乗算する通常の方法を使います。 –