5

我正在尝试使用 gcc 编译器在 linux 下编译此代码:

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 位寄存器(%esp 在 x64 上根本没有意义)。

于 2013-01-05T12:56:47.017 回答
4

虽然以上是正确的,但我希望它实际上不是正确的解决方案。如果你为 x86-64 编译它,你应该使用 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"clobber 可能是安全的。

我重新排列了指令,因为大多数指令不能使用 64 位立即数。(虽然这个特定的常量确实适合带符号的 32 位 imm32,所以and $imm, %rax本来可以,但是这样做可能更有效,因为它避免在 AND 之前复制 RSP。该常量不适合 imm8,所以两种方式都有相同的代码大小。)

您可以%0将堆栈指针向下舍入到 4k 页面的开头,而不是破坏 RAX。替换模板字符串中的任何地方,并删除%%raxclobber 。或者只是使用内联 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 移动 %rsp,%rax
   3: 48 25 00 f0 ff ff 和 $0xfffffffffffff000,%rax
   9:c3 retq

分别对于 32 位:

部分.text的反汇编:

00000000 <get_current>:
   0: 89 e0 移动 %esp,%eax
   2: 25 00 f0 ff ff 和 $0xfffff000,%eax
   7:c3 ret

gcc 的内联汇编器的一大优点是能够将变量绑定到寄存器,是的,如图所示,它可以sp在 x86 上识别。

编辑:哎呀......刚刚注意到 gcc 3.4.5 为上面创建了有趣的代码 - 即使在高优化级别,它通常会自行消除帧指针,上面的源代码将创建一个帧指针(对于非静态函数的实例化)。在 gcc 3.4.5 上显式编译-fomit-frame-pointer或使用 gcc 4.x 会创建现在显示的正确代码(有关 gcc 3.4.5 的作用,请参阅发布历史记录)。

于 2013-02-19T18:27:34.540 回答