GCC内联ASM保证

时间:2013-07-02 21:16:47

标签: c++ c assembly inline-assembly

我认为这是一个简单的问题,但我找不到任何东西。 如果我写

void bar()
{
    {
        void *rax = 0/* ...*/, *rbx = 0/* ... */;
        asm volatile ("movq %0, %%rax; movq %1, %%rbx;" : : "m"(rax), "m"(rbx));
        goto foo;    
    }

    {
        foo:
        void* rax, *rbx;
        asm volatile ("movq %%rax, %0; movq %%rbx, %1;" : "=m"(rax), "=m"(rbx));

        // LOTS OF CODE
    }
}

是否可以保证在运行第二个块中的任何其他代码之前我可以获取rax / rbx的值?

2 个答案:

答案 0 :(得分:3)

否 - 编译器根据其在asm语句之前/之后立即分配的寄存器/存储器位置的约束来挂接输入/输出值,并假定其他寄存器不受影响。因此,在您的情况下,它可能会将一些重要内容放入%%eax%%ebx中,这些内容正在破坏(这可能会导致崩溃或其他不当行为)。

每当你在asm语句中使用固定寄存器时,你必须在clobbers列表中列出这些寄存器(除非你使用映射到特定寄存器的约束)。所以至少你需要:

asm volatile ("movq %0, %%rax; movq %1, %%rbx;" : : "m"(rax), "m"(rbx) : "rax", "rbx");

对于你的asm语句 - 但即便如此,也没有编译器不会提出的保证 在你的第一个asm块之后和第二个asm块之前的其他内容(破坏你想要保存的值)。

答案 1 :(得分:1)

在gcc中使用volatileasm将保证编译器不会重新排序声明。但是,不能保证编译器不会在foo:标签和内联asm语句之间添加额外的代码。当然,这意味着您不能依赖于该部分中保留的寄存器值 - 我没有设法提出一个明显的例子,但我很确定编译器不保证这可以不会发生。