5

Linuxでgccコンパイラを使用してこのコードをコンパイルしようとしています:

static inline unsigned long get_current(void)
{
    unsigned long current;

    asm volatile (
    " movl %%esp, %%eax;"
    " andl %1, %%eax;"
    " movl (%%eax), %0;"
    : "=r" (current)
    : "i" (0xfffff000)
    );
    return current;
}

しかし、私はこのエラーが発生しています:

program.c: Assembler messages: program.c:455: Error: incorrect
register `%rbx' used with `l' suffix

ここで何が悪いのですか?

4

3 に答える 3

5

明らかに、64 ビット用にコンパイルしています。必要ない場合は gcc -m32 を使用するか、64 ビット レジスタを使用してみてください (x64 では %esp はまったく意味がありません)。

于 2013-01-05T12:56:47.017 に答える
4

上記はある程度正しいですが、実際には正しい解決策ではないと思います。これを x86-64 用にコンパイルする場合は、「get current」に 64 ビット操作を使用する必要があります。((カーネル?)スタックがまだ1ページしかない場合、そうでない場合は、スタックの下部を計算するために別のマスク定数が必要になります。)

asm volatile (
  " movq %1, %%rax \n"
  " andq %%rsp, %%rax;"         // discard the low 12 bits
  " movq (%%rax), %0;"
  : "=r" (current)
  : "i" (0xfffffffffffff000)
  : "rax"       // Remember to mark any temporary registers modified in "clobber"
    , "memory"  // and we read memory at an address that might hold a C object
);

このメモリ位置がプレーンな C で書かれていない場合は、"memory"クロバーを省略しても安全かもしれません。

ほとんどの命令では 64 ビットの即値を使用できないため、命令を再配置しました。(この特定の定数は符号付きの 32 ビット imm32 に適合するのでand $imm, %rax問題ありませんでしたが、AND の前に RSP をコピーすることを回避するため、この方法で行う方が効率的である可能性があります。定数は imm8 に適合しないため、両方の方法でコードサイズは同じです。)

RAX を上書きする代わりに%0、スタック ポインターを 4k ページの先頭に切り下げるための一時的なものとして使用できます。テンプレート文字列のすべての場所を置き換え%%rax、クロバーを削除します。または、インライン asm を使用して を取得し、C でロード部分を実行します。%0"rax"uintptr_t rsp*(volatile uinptr_t*)(rsp & -4096)

于 2013-01-05T16:28:21.387 に答える
3

私はこれを次のようにコーディングします:

static inline unsigned long get_current(void)
{
    unsigned register long current asm("sp");

    asm volatile ("" : "=r"(current));

    return (current & ~ (unsigned long)0xfff);
}

これは 64 ビットと 32 ビットの両方でコンパイルされます。次のコードを作成します。

セクション .text の分解:

0000000000000000 <get_current>:
   0: 48 89 e0 mov %rsp,%rax
   3: 48 25 00 f0 ff ff および $0xffffffffffffff000,%rax
   9: c3 retq

それぞれ、32 ビットの場合:

セクション .text の分解:

00000000 <get_current>:
   0: 89 e0 mov %esp,%eax
   2: 25 00 f0 ff ff および $0xfffff000,%eax
   7: c3 ret

gcc のインライン アセンブラの気の利いた機能の 1 つは、変数をレジスタにバインドする機能です。はい、示されているように、spx86 で認識されます。

編集:おっと... gcc 3.4.5が上記の面白いコードを作成することに気づきました-通常はフレームポインターを独自に排除する高い最適化レベルでも、上記のソースはフレームポインターを作成します(非静的関数のインスタンス化)。gcc 3.4.5で明示的にコンパイルする-fomit-frame-pointerか、gcc 4.x を使用すると、現在表示されている正しいコードが作成されます (gcc 3.4.5 の機能については、投稿履歴を参照してください)。

于 2013-02-19T18:27:34.540 に答える