【发布时间】:2012-06-12 21:27:38
【问题描述】:
我需要保存一个寄存器的值(即[ar]ax)。它在函数调用后被修改,但该值需要稍后使用。 我想到了三种方法(示例是 64 位):
1.入栈:
__asm__ ("pushq %rax\n\t"
"call function\n\t"
"popq %rax");
2.保存在寄存器中:
__asm__ ("movq %%rax, %%some_register\n\t"
"call function\n\t"
"movq %%some_register, %%rax"
: : : "%some_register");
3.将其保存在变量中:
unsigned long var;
__asm__ ("movq %%rax, %0" : "=m" (var) : : );
function();
__asm__ ("movq %0, %%rax" : : "m" (var) : );
目前,我正在使用#1。它在我的特定情况下按预期工作,但我担心将它推入堆栈可能是一件坏事™。我最担心的是:编译器不“知道”它被推送。由于它似乎占用了堆栈帧的一些空间,而这相当有限,这通常会导致麻烦。
将它保存在寄存器中可以防止编译器根据自己的需要使用它。这在 x86-64 上可能不是什么大问题,与 x86 相比,这里有许多额外的寄存器。但如果我需要在 x86 上使用它,那可能会影响性能,因为那里的寄存器数量要有限得多。
将其保存到变量可能是最佳选择。而且由于编译器可能会将变量保存在堆栈上 && 甚至分配一个寄存器,所以它可能不会那么慢。但这确实让代码看起来很奇怪,而且还有一个额外的变量可能会让其他人摸不着头脑。
所以问题是:哪种解决方案是最好的,即 Right Thing™ 应该做什么?或者也许还有一些我没有想到的方法来保存它 - 那些会更好?
注意:如果重要的话,该函数不接受变量并且不返回任何内容;寄存器中的值不能简单地通过一些“更高级别”的解决方案来保存,因此是内联汇编;它必须是 [er]ax ;我还没有测试第三种解决方案,所以它可能有点不准确。
【问题讨论】:
-
为什么不能用内联此代码的编程语言创建局部变量。然后将寄存器保存到其中。您的语言范围将保留 var,直到您的函数返回。
-
另一种可能性是使用 r12-r15,它们是被调用者保存的寄存器。一般来说,在任何情况下检查生成的组件是明智的。内联汇编可以以非常隐蔽的方式抑制编译器优化。
-
@kingchris 那将是解决方案#3。问题是我需要该值在使用时专门位于 [er]ax 寄存器中。如果没有我所知道的 inline-asm,就无法可靠地确保寄存器保持该值。我不能用 c++ 写它(这就是我使用的)。
-
@horsh 我想到了这一点并写了这篇文章(在我写了我对使用寄存器的担忧的部分。但我没有明确命名 r12-r15)。正如我所写,我担心的是——在 x86(32 位)上,这些寄存器不存在,因此我必须使用极少数可用的寄存器之一。以及阻止编译器使用它。
-
好吧,如果你解释一下为什么我必须在 [er]ax 也许我们可以想到可能的副作用。它必须在函数调用之前在 [er]ax 中,还是在函数调用之后使用它。
标签: x86 stack x86-64 inline-assembly cpu-registers