[英]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.