1

gccでインラインasm機能をテストしたいと思います。そのため、ubuntu 12.04 64ビットで次のコードを入力してコンパイルしましたが、実行時にシステムに「セグメンテーション違反」が画面に表示されます。問題の原因がわかりません。

#include <stdio.h>
char Format[]="Hello world %d\n";
int main()
{
    asm
    (
        "movl $3,4(%esp);"
        "movl $Format,(%esp);"
        "call printf;"
    );
    return 0;
}

プログラム初心者を助けてくれてありがとう。このコードを書くためのIDEとしてCode::blocksを使用しています。%rdxなどの64ビットレジスタを使用しようとしましたが、ビルドメッセージのログに、コードのコンパイル時に「エラー:レジスタ名 `%rdx'が不正です」と表示されます。これは、Code ::blocksによって呼び出されるgccが32ビットバージョンであるため、それらのレジスタを認識できないことを意味すると思います。スタックスペースを予約するようにコードを変更します

#include <stdio.h>
char Format[]="Hello world %d\n";
int main()
{
    asm
    (
        "subl $8,%esp;"         //I  don't know  $4, $8, $12, $16, $20 which is correct
                                        //but I had tried them all but results are still  ''segmentation fault."
        "movl $3,4(%esp);"
        "movl $Format,(%esp);"
        "call printf;"
        "movl %ebp,%esp;"
    );
    return 0;
}

コンパイラオプションとして-m32を使用することもできますが、それでも「セグメンテーション違反」が表示されます。

助けてくれてありがとう。

4

2 に答える 2

5

System V ABI for x64は、関数への最初の6つの整数/ポインター引数をレジスター、、、、、および%rdi%rsi入れること%rdxを義務付けています。スタックは、さらに引数を渡すために使用されます。また、可変数の引数(など)を使用して関数を呼び出す場合は、レジスタに渡される浮動小数点引数の総数に設定する必要があります。あなたの場合に呼び出す正しい順序は次のとおりです。%rcx%r8%r9printf%raxXMMprintf()

xorl %eax, %eax
movl $Format, %edi
movl $3, %esi
call printf

%rax0浮動小数点引数が渡されていないため、に設定する必要があります。このコードは、初期化されたデータのVAが通常最初の4 GiBのどこかにあるという事実も使用しているため、より短い32ビット命令が使用されます。もちろん、フォーマット文字列がメモリ内のどこにあるかを判断するprintfために、の完全なコンテンツを引き続き調べます。%rdi

コードは32ビットの呼び出し規約を使用しており、32ビットとしてクロスコンパイルすると理論的には機能し-m32ますが、最初にのようなものを使用して引数用のスタックスペースを予約し、を使用しsubl $20, %espて呼び出した後に復元するaddl %20, %esp必要があります。そうしないと、スタックが上書きされます。main()または間違った差出人住所をret選択します。これは、32ビットモードでコンパイルおよび実行される完全に機能する(テスト済みの)C/asmコードです。

#include <stdio.h>

char Format[] = "Hello world, %d\n";

int main (void)
{
   asm
   (
      // Make stack space for arguments to printf
      "subl $8, %esp\n"
      "movl $3, 4(%esp)\n"
      "movl $Format, (%esp)\n"
      "call printf\n"
      // Clean-up the stack
      "addl $8, %esp\n"
   );
   return 0;
}

$ gcc -m32 -o test.x test.c
$ ./test.x
Hello world, 3

備考:各アセンブリ行の最後では\nなく;、コンパイラアセンブリ出力の可読性を向上させるためにのみ使用します。これは、コードの正確性とは無関係です。

于 2012-07-07T20:37:07.720 に答える
4

最初に通常の C プログラムを見て、それがどのような asm を提供するかを確認してみてください ( を使用して取得できますgcc -S)。

次に、呼び出しに必要な ASM の部分を特定しprintf、元のプログラムで再現します。

ここにあるのは、呼び出し 規約エラーです。

于 2012-07-07T20:02:21.463 に答える