【发布时间】:2019-05-30 01:57:02
【问题描述】:
我正在简要研究用于 amd64 / x86-64 架构的 System V ABI,我很好奇它如何处理超过 128 位的返回值,其中 rax 和 rdx 还不够。
我在 Ubuntu 18.04 64 位(更一般地说,任何兼容 amd64 POSIX 的系统)上编写了以下 C 代码:
struct big {
long long a, b, c, d;
};
struct big bigfunc(void) {
struct big r = {12, 34, 56, 78};
return r;
}
编译为gcc -S -masm=intel t.c,检查t.s:
.file "t.c"
.intel_syntax noprefix
.text
.globl bigfunc
.type bigfunc, @function
bigfunc:
.LFB0:
.cfi_startproc
mov QWORD PTR -40[rsp], rdi
mov QWORD PTR -32[rsp], 12
mov QWORD PTR -24[rsp], 34
mov QWORD PTR -16[rsp], 56
mov QWORD PTR -8[rsp], 78
mov rcx, QWORD PTR -40[rsp]
mov rax, QWORD PTR -32[rsp]
mov rdx, QWORD PTR -24[rsp]
mov QWORD PTR [rcx], rax
mov QWORD PTR 8[rcx], rdx
mov rax, QWORD PTR -16[rsp]
mov rdx, QWORD PTR -8[rsp]
mov QWORD PTR 16[rcx], rax
mov QWORD PTR 24[rcx], rdx
mov rax, QWORD PTR -40[rsp]
ret
.cfi_endproc
.LFE0:
.size bigfunc, .-bigfunc
.ident "GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0"
.section .note.GNU-stack,"",@progbits
毫不奇怪,结构定义没有编译成任何指令,所以输出只包含函数bigfunc。输出程序集看起来非常简单,从堆栈中为 struct big r 分配内存并分配初始值,然后返回它。
如果我理解正确,在执行ret 之前,寄存器rax 在函数调用的开头包含rdi 的值(来自QWORD PTR -40[rbp])。根据 SysV,rdi 是提供给函数的第一个参数,这是不可能的,因为函数不接受任何参数。所以我在这里有几个问题:
- 当函数
bigfunc不带参数时,rdi是什么? - 什么是
rax(作为包含返回值的寄存器),当rdx在这个函数中没有被触及? - 函数如何返回这个 256 位 C 结构?
【问题讨论】:
-
如果启用优化,这段代码会更容易理解。 TL;DR:正如ABI document 中所指定的,通过将指向结构的指针作为隐藏的第一个参数传递来返回结构。
-
@fuz 浏览菜单但没有找到关键字“返回值”。介意指出节号吗?谢谢。
-
它可能不在 amd64 特定的文档中 - 这是适用于所有架构的一般规则。
-
@iBug 见第 22 页。这是 §3.2.3 的全部内容。
-
@WumpusQ.Wumbley:什么?由每个架构上的每个调用约定/ABI 来指定返回多大的对象。例如如果在回退到内存之前使用了多个寄存器,以及内存是否传递隐藏指针(通常作为第一个 arg,但需要指定详细信息;它可以传入通常不是传递 arg 的寄存器的寄存器)或将值留在堆栈上(与 args 的 callee-pops 相反),或其他任何东西。
标签: assembly posix return-value x86-64 abi