1

我需要保留一个寄存器的值([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 ;我还没有测试第三种解决方案,所以它可能有点不准确。

4

2 回答 2

0

在解决方案 2 中,认为寄存器不会被破坏是大胆的,尤其是在优化时。解决方案 1 的唯一缺点是您将无法展开堆栈(如果您需要调试函数调用堆栈),因为堆栈帧之间的唯一链接是推送的 [er]bp,在这种情况下它不再是与 [er] sp 一致。我肯定会选择更清晰的解决方案 3。当然它为一些混淆目的添加了一个局部变量,但至少它不会欺骗 ABI!

于 2012-06-09T17:40:25.420 回答
0

None of your methods are correct, you can not safely keep something in a register outside of an asm statement. If you wish to pass a value between asm statements you must store it in a variable, GCC will keep it in the register if can, if not it will save it somewhere.

于 2012-06-17T18:05:09.893 回答