GCC内联ASM保证

GCC inline ASM guarantees

本文关键字:保证 ASM 内联 GCC      更新时间:2023-10-16

我认为这是一个简单的问题,但我什么都找不到。如果我写

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的值?

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

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

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

对于您的asm语句,但即使这样,编译器也不会提供任何保证在您的第一个asm块之后和第二个asm区块之前,将其他东西放入%%eax%%ebx中(破坏您试图保存的值)

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