我认为这是一个简单的问题,但我找不到任何东西。 如果我写
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的值?
答案 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中使用volatile
和asm
将保证编译器不会重新排序声明。但是,不能保证编译器不会在foo:
标签和内联asm
语句之间添加额外的代码。当然,这意味着您不能依赖于该部分中保留的寄存器值 - 我没有设法提出一个明显的例子,但我很确定编译器不保证这可以不会发生。