4

私は次のコードを持っています:

#include <stdio.h>
void main(){
    int x=0, y=0,i=100;
    for (;i<1000; i++,x+=32){
        if (x == 25*32) {
            y+=32;
            asm volatile("pushl %%eax\n\t"
                         "movl $0, %%eax\n\t"
                         "popl %%eax\n\t"
                         :"=a"(x)
                         :"a"(0)
                         );
        }
        printf("%d %d\n", x, y);
    }
}

基本的に、私がやりたいのは、変数xを0に設定することですが、アセンブリコードが何をするのかよくわかりません。実際には、xを0に設定しますが、何が起こっているのかわかりません。誰かが何が起こっているのか説明できますか?(アセンブリとCを学習するためだけに)。

4

1 に答える 1

5

asmコンストラクトの内容は次のとおりです。

  • "=a"(x)、アセンブリが=%eax(a)レジスタに()を書き込むことをコンパイラに通知し、コンパイラにその結果をx()に割り当てさせます(x)
  • で、%eax()に"a"(0)0()を入れるようにコンパイラに指示すると、アセンブリはそれを読み取ります。(0)a
  • 次にpush %%eax、%eaxをスタックに保存しmovl $0, %%eax、0を%eaxに入れpopl %%eaxて、保存した値を%eaxに復元します。

したがって、何が起こるかは次のとおりです。

  • コンパイラは%eaxに0を入れます。
  • あなたの指示はスタックに0を保存し、0を%eaxに移動し、スタックから0を復元します。
  • コンパイラは、%eaxの0をxの値として使用します。

したがって、これは機能しますが、非効率的です。これで同じ効果を得ることができます:

asm volatile("movl $0, %[MyName]"
    : [MyName] "=r" (x)
);

これが言うことは:

  • 入力はありません(2番目の「:」がないため)。
  • 前と同じように、=これらの命令が結果を書き込むようにコンパイラに指示します。
  • r結果がレジスタに書き込まれると言っていますが、コンパイラはレジスタを選択します。
  • は、アセンブリコードに表示される場所を、コンパイラが選択するレジスタの名前に[MyName]変更するようにコンパイラに指示します。%[MyName]
  • 前と同じように、(x)はアセンブリコードの後のレジスタの値をxの新しい値として使用するように言っています。
  • 最後に、命令movl $0, %[MyName]は0を%[MyName]で指定されたレジスタに移動するように指示します。

コンパイラはレジスタを選択するため、アセンブリ言語でレジスタを保存および復元する必要はありません。コンパイラーは、他のレジスターを必要としないことを確認する責任があります。

私が行ったようにオペランドに名前を付けることができるの[MyName]は、GCCの新機能です。お使いのバージョンにそれがない場合は、代わりにこれを行うことができます:

asm volatile("movl $0, %0"
    : "=r" (x)
);

名前がない場合、各オペランドは0から始まり、入出力指定子にオペランドが表示される順序で増分される番号を取得します。オペランドが1つしかないため、%0でした。

于 2012-08-24T13:28:31.810 に答える