System V AMD64 ABI 调用约定是这样规定的:
寄存器
%rbp
,%rbx
并%r12
通过%r15
“属于”调用函数,并且被调用函数需要保存它们的值。换句话说,被调用函数必须为其调用者保留这些寄存器的值。剩余的寄存器“属于”被调用的函数。如果调用函数想要在函数调用中保留这样的寄存器值,它必须将值保存在其本地堆栈帧中。
例如,给定以下代码:
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);
}
装配表示为:
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
在本例中,参数已传入%edi
,%xmm0
和%rsi
。调用约定规定这些寄存器“属于”被调用函数,这意味着f1
没有义务保留它们的值。事实上,%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
我想保留所有参数寄存器。文档说明该值可以保存在我尝试过的本地堆栈中,如下所示:
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 ));
}
这会生成以下内容:
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
这似乎不会恢复 的值%edi
。保存所有参数/参数寄存器的正确方法是什么?