gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 01:38:10 24 4
gpt4 key购买 nike

System V AMD64 ABI call convention因此被强制要求:

Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling function and the called function is required to preserve their values. 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.

例如,给定这段代码:

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 的值。保留所有参数/参数寄存器的正确方法是什么?

最佳答案

你不能像这样混合使用 C 和 asm。特别是,在内联汇编中执行单独的 push 或 pop 指令会严重破坏事情;任何给定的内联汇编 block 在堆栈指针上的净偏移量必须为 0。

实际上,ABI 文档与内联汇编的使用相当不相关。为此,您需要遵循 GCC 内联 asm 契约(Contract),记录您将哪些寄存器用于输入和输出以及 clobber 列表中的内容。如果您在汇编器中编写整个函数(在 .s 文件而不是 .c 文件中),则 ABI 是相关的。

关于c - 如何在 x86-64 下保留参数/参数寄存器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10761934/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com