2

もう一度、MinGW インライン アセンブリで遊んでみます。

#include <stdio.h>

int foobar(int);

int main(){
 int n = 0;
 printf("Number: ");
 scanf("%d", &n);
 printf("\n%d",foobar(n));
 return 0;
}

int foobar(int num){
 int result = 0;
 asm(".intel_syntax noprefix\n");
 asm("mov eax, num\n");
 asm("add eax, 110b\n");
 asm("sub eax, 2\n");
    asm("mov result, eax\n");
 return result;
}

それをコンパイルします。

C:\Users\Andre\Codes>gcc asmtest.c -o asmtest -masm=intel

エラーがあります:

C:\Users\Andre\AppData\Local\Temp\ccqny4yb.s: アセンブラー メッセージ: C:\Users\Andre\AppData\Local\Temp\ccqny4yb.s:53: エラー: 不明なラベルへの後方参照 "110:"

ここで何が問題なのですか?私のコードはすでに有効だと思いますか?

4

1 に答える 1

1

GCC は AT&T スタイルのアセンブリで最適に動作し、GAS はすべての Intel 構文を実装しているわけではありません。あなたの差し迫った問題は110b、数字として解釈されないことに起因しますが、それだけではありません.

GCC のインライン アセンブラー構文では、変数を直接参照することはできません。次のように記述する必要があります (デフォルトを使用-masm=att):

int foobar(int num) {
    int result;
    asm("mov %1, %%eax\n\t"
        "add $6, %%eax\n\t"
        "sub $2, %%eax\n\t"
        "mov %%eax, %0"
        : "=g" (result)
        : "g" (num)
        : "eax", "cc");
    return result;
}

最初のコロンの後には、出力オペランドのコンマ区切りリストがあります。"=g" (result) が最初の制約であるため、 resultalias を取得し%0ます。 任意の汎用レジスタまたはメモリである可能性があり、書き込みのみが行われる"=g"GCC に示します。%0(+代わりに、=読み書きを示します。GCC は複数の目的で同じレジスタを再利用することを決定する場合があるため、すべてがどのように使用されるかを正確に伝えることを明示する必要があります。)

2 番目のコロンの後には、入力オペランドのコンマ区切りリストがあります。"g" (num)は 2 番目の制約であるため、 numalias を取得し%1ます。 "g"からのみ読み取られることを意味します。

3 番目のコロンの後には、クロバーのカンマ区切りリストがあります。これは、インラインアセンブリがこれらのレジスタ/メモリを入力でも出力でもない場合でも変更する可能性があることを GCC に通知するため、GCC はインラインアセンブリ全体で保持していた情報を再ロードする必要があります。ここでは、明らかに を変更%eaxし、条件コード (フラグ) レジスタも の影響を受けadd/subます。

コンパイラが生成するアセンブリを見てください。

$ cc -S -o- -m32 asmtest.c | sed -n /globl.foobar/,/-foobar/p
.globl フーバー
        .type foobar、@関数
フーバー:
        pushl %ebp
        movl %esp, %ebp
        サブル $16、%esp
#アプリ
#15「asmtest.c」1
        mov 8(%ebp), %eax
        $6、%eax を追加
        サブ $2、%eax
        mov %eax, -4(%ebp)
#0""2
#NO_APP
        movl -4(%ebp), %eax
        離れる
        戻る
        .size foobar、.-foobar

コンパイラは、 と のスタック位置を直接使用することを決定しましnumresult:"=r":"r"(レジスタまたはメモリ位置を許可する) 代わりに制約 (レジスタのみが許可されることを意味する)を使用した場合:"=g":"g"、コンパイラはインライン アセンブリの前後にそれらをレジスタとの間でコピーします。

$ cc -S -o- -m32 asmtest.c | sed -n /globl.foobar/,/-foobar/p
.globl フーバー
        .type foobar、@関数
フーバー:
        pushl %ebp
        movl %esp, %ebp
        サブル $16、%esp
        movl 8(%ebp)、%edx
#アプリ
#15「asmtest.c」1
        mov %edx, %eax
        $6、%eax を追加
        サブ $2、%eax
        mov %eax, %edx
#0""2
#NO_APP
        movl %edx, -4(%ebp)
        movl -4(%ebp), %eax
        離れる
        戻る
        .size foobar、.-foobar

本当に Intel 構文を使用したい場合は、それを別の.sソース ファイルに入れ、 NASMで個別にアセンブルしてから、オブジェクトをリンクしてください。

$猫 asmtest.c
#include <stdio.h>

int foobar(int);
/* int foobar(int) __attribute__((fastcall)); */

int main() {
    int n = 0;
    printf("番号: ");
    scanf("%d", &n);
    printf("%d\n", foobar(n));
    0 を返します。
}
$ cat foobar.s
グローバルフーバー
フーバー:
        mov eax,[esp+4] # C プロトタイプが fastcall とマークされている場合、この行を削除します
        サブ eax、110b
        eax,2 を追加
        戻る
$ nasm -f elf foobar.s 
$ cc -m32 asmtest.c foobar.o 
$ ./a.out
番号: 30
26

(ただし-f elf、Windows では正しくありません。たぶん-f win32? Windows の愚かさのために_foobar、アセンブリで名前を使用する必要がある場合があります。)

于 2010-02-27T05:40:14.863 に答える