简体   繁体   English

如何在x86-64下保留参数/参数寄存器?

[英]How to preserve argument/parameter registers under x86-64?

The System V AMD64 ABI call convention is mandated thus: 因此强制要求System V AMD64 ABI呼叫约定

Registers %rbp , %rbx and %r12 through %r15 “belong” to the calling function and the called function is required to preserve their values. 寄存器%rbp%rbx%r12%r15 “属于”调用函数,并且需要被调用函数来保存它们的值。 In other words, a called function must preserve these registers' values for its caller. 换句话说,被调用函数必须为其调用者保留这些寄存器的值。 Remaining registers “belong” to the called function. 剩余寄存器“属于”被调用函数。 If a calling function wants to preserve such a register value across a function call, it must save the value in its local stack frame. 如果调用函数想要在函数调用中保留这样的寄存器值,则必须将该值保存在其本地堆栈帧中。

For example, given this code: 例如,给定此代码:

void f1(const int i, const double j, const char * k)
{
    printf("i = %d\n", i);
    printf("j = %g\n", j);
    printf("k = %s\n", k);
}

The assembly representation is: 汇编表示为:

f1():
  4004f4:   55                      push   %rbp
  4004f5:   48 89 e5                mov    %rsp,%rbp
  4004f8:   48 83 ec 20             sub    $0x20,%rsp
  4004fc:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004ff:   f2 0f 11 45 f0          movsd  %xmm0,-0x10(%rbp)
  400504:   48 89 75 e8             mov    %rsi,-0x18(%rbp)
  400508:   b8 70 06 40 00          mov    $0x400670,%eax
  40050d:   8b 55 fc                mov    -0x4(%rbp),%edx
  400510:   89 d6                   mov    %edx,%esi
  400512:   48 89 c7                mov    %rax,%rdi
  400515:   b8 00 00 00 00          mov    $0x0,%eax
  40051a:   e8 d1 fe ff ff          callq  4003f0 <printf@plt>
  40051f:   b8 78 06 40 00          mov    $0x400678,%eax
  400524:   f2 0f 10 45 f0          movsd  -0x10(%rbp),%xmm0
  400529:   48 89 c7                mov    %rax,%rdi
  40052c:   b8 01 00 00 00          mov    $0x1,%eax
  400531:   e8 ba fe ff ff          callq  4003f0 <printf@plt>
  400536:   b8 80 06 40 00          mov    $0x400680,%eax
  40053b:   48 8b 55 e8             mov    -0x18(%rbp),%rdx
  40053f:   48 89 d6                mov    %rdx,%rsi
  400542:   48 89 c7                mov    %rax,%rdi
  400545:   b8 00 00 00 00          mov    $0x0,%eax
  40054a:   e8 a1 fe ff ff          callq  4003f0 <printf@plt>
  40054f:   c9                      leaveq 
  400550:   c3                      retq  

In this instance, the parameters have been passed in %edi , %xmm0 and %rsi . 在这种情况下,参数已在%edi%xmm0%rsi传递。 The call convention states that these registers "belong" to the called function and this means f1 has no obligation to preserve their values. 调用约定规定这些寄存器“属于”被调用函数,这意味着f1没有义务保留它们的值。 In fact, %edi , %xmm0 and %rsi are all trashed on the following lines: 实际上, %edi%xmm0%rsi都在以下行中被删除:

400510: 89 d6                   mov    %edx,%esi
400512: 48 89 c7                mov    %rax,%rdi
..
400524: f2 0f 10 45 f0          movsd  -0x10(%rbp),%xmm0

I want to preserve all argument registers. 我想保留所有参数寄存器。 The documentation states the value can be saved on the local stack which I have tried as follows: 文档说明值可以保存在本地堆栈上,我尝试过如下:

void f1(const int i, const double j, const char * k)
{
    uint32_t edi;
    __asm ("movl %%edi, %0;" : "=r" ( edi ));

    printf("i = %d\n", i);
    printf("j = %g\n", j);
    printf("k = %s\n", k);

    __asm ("movl %0, %%edi;" : "=d"( edi ));
}

This generates the following: 这会生成以下内容:

f1():
  4004f4:   55                      push   %rbp
  4004f5:   48 89 e5                mov    %rsp,%rbp
  4004f8:   53                      push   %rbx
  4004f9:   48 83 ec 38             sub    $0x38,%rsp
  4004fd:   89 7d dc                mov    %edi,-0x24(%rbp)
  400500:   f2 0f 11 45 d0          movsd  %xmm0,-0x30(%rbp)
  400505:   48 89 75 c8             mov    %rsi,-0x38(%rbp)
  400509:   89 fb                   mov    %edi,%ebx
  40050b:   89 5d ec                mov    %ebx,-0x14(%rbp)
  40050e:   b8 80 06 40 00          mov    $0x400680,%eax
  400513:   8b 55 dc                mov    -0x24(%rbp),%edx
  400516:   89 d6                   mov    %edx,%esi
  400518:   48 89 c7                mov    %rax,%rdi
  40051b:   b8 00 00 00 00          mov    $0x0,%eax
  400520:   e8 cb fe ff ff          callq  4003f0 <printf@plt>
  400525:   b8 88 06 40 00          mov    $0x400688,%eax
  40052a:   f2 0f 10 45 d0          movsd  -0x30(%rbp),%xmm0
  40052f:   48 89 c7                mov    %rax,%rdi
  400532:   b8 01 00 00 00          mov    $0x1,%eax
  400537:   e8 b4 fe ff ff          callq  4003f0 <printf@plt>
  40053c:   b8 90 06 40 00          mov    $0x400690,%eax
  400541:   48 8b 55 c8             mov    -0x38(%rbp),%rdx
  400545:   48 89 d6                mov    %rdx,%rsi
  400548:   48 89 c7                mov    %rax,%rdi
  40054b:   b8 00 00 00 00          mov    $0x0,%eax
  400550:   e8 9b fe ff ff          callq  4003f0 <printf@plt>
  400555:   89 d7                   mov    %edx,%edi
  400557:   89 d3                   mov    %edx,%ebx
  400559:   89 5d ec                mov    %ebx,-0x14(%rbp)
  40055c:   48 83 c4 38             add    $0x38,%rsp
  400560:   5b                      pop    %rbx
  400561:   5d                      pop    %rbp
  400562:   c3                      retq   

This does not appear to be restoring the value of %edi . 这似乎没有恢复%edi的值。 What is the correct way for preserving all the argument/parameter registers? 保留所有参数/参数寄存器的正确方法是什么?

You can't mix C and asm like this. 你不能像这样混合C和asm。 In particular, executing an isolated push or pop instruction in inline assembly will horribly break things; 特别是,在内联汇编中执行隔离的push或pop指令会严重破坏事物; any given inline assembly block must have a net offset of 0 on the stack pointer. 任何给定的内联汇编块必须在堆栈指针上具有0的净偏移量。

Really, the ABI document is rather irrelevant to the use of inline asm. 实际上,ABI文档与内联asm的使用无关。 For that, you need to follow the GCC inline asm contract of documenting which registers you use for input and output and what's in the clobber list. 为此,您需要遵循GCC内联asm合同,记录您用于输入和输出的寄存器以及clobber列表中的内容。 The ABI is relevant if you're writing entire functions in assembler (in a .s file not a .c file). 如果您在汇编程序中编写整个函数(在.s文件中而不是.c文件中),则ABI是相关的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM