X86 我应该推动堆栈,使用寄存器还是变量?

X86 我应该推动堆栈,使用寄存器还是变量?,x86,stack,x86-64,inline-assembly,cpu-registers,X86,Stack,X86 64,Inline Assembly,Cpu Registers,我需要保留寄存器[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 %%s

我需要保留寄存器[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-64有许多额外的寄存器。但是如果我需要在x86上使用它,这可能会对性能造成影响,因为那里的寄存器数量非常有限

将其保存到变量可能是最佳选择。而且由于编译器可能会将变量保存在堆栈上&&甚至分配一个寄存器,因此它可能不会那么慢。但这确实让代码看起来很奇怪,还有一个额外的变量可能会让其他人挠头

所以问题是:哪种解决方案是最好的,即什么是正确的™ 怎么办?或者也许有更多的方法来保存它,我没有想到——那些会更好


注意:该函数不接受变量,也不返回任何内容,如果这很重要的话;寄存器中的值不能简单地通过某个更高级别的解决方案来保存,因此需要内联asm;必须是(呃)ax,;我还没有测试第三个解决方案,所以可能有点不准确

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

您的方法都不正确,您无法在asm语句之外的寄存器中安全地保留某些内容。如果希望在asm语句之间传递值,则必须将其存储在变量中,如果可以,GCC会将其保存在寄存器中,如果不能,GCC会将其保存在某个位置。

为什么不能在将此代码内联到的编程语言中创建局部变量。然后将寄存器保存到该位置。在函数返回之前,语言的作用域将保持变量不变。另一种可能性是使用r12-r15,这是被调用方保存的寄存器。一般来说,在任何情况下检查结果总成都是明智的。内联asm可以以非常模糊的方式抑制编译器优化。@这就是解决方案3。问题是我需要在使用[er]ax寄存器时将该值专门放在其中。我知道,如果没有内联asm,就无法可靠地确保寄存器保存该值。我不能用C++来写它,这就是我所用的。@霍什,我想到了这一点,并在我写的关于使用登记器的部分写了这篇文章。但我并没有明确命名r12-r15。我担心的是,正如我所写的,在x86 32位上,这些寄存器不存在,因此我必须使用极少数可用寄存器中的一个。以及阻止编译器使用它。如果你解释为什么我必须在[er]ax中,也许我们可以想到可能的副作用。它必须在函数调用之前在[er]ax中,或者在函数调用之后使用它。