【问题标题】:How are C structs returned [duplicate]C结构如何返回[重复]
【发布时间】:2021-09-09 01:06:12
【问题描述】:

我想知道一个结构是如何返回的:

typedef struct number {
   uint64_t a, b, c, d;
}number;


number get_number(){
   number res = {0,0,0,0};
   return res;
}

反汇编成

0000000000001149 <get_number>:
    1149:   55                      push   rbp
    114a:   48 89 e5                mov    rbp,rsp
    114d:   48 89 7d d8             mov    QWORD PTR [rbp-0x28],rdi
    1151:   48 c7 45 e0 00 00 00    mov    QWORD PTR [rbp-0x20],0x0
    1158:   00
    1159:   48 c7 45 e8 00 00 00    mov    QWORD PTR [rbp-0x18],0x0
    1160:   00
    1161:   48 c7 45 f0 00 00 00    mov    QWORD PTR [rbp-0x10],0x0
    1168:   00
    1169:   48 c7 45 f8 00 00 00    mov    QWORD PTR [rbp-0x8],0x0
    1170:   00
    1171:   48 8b 4d d8             mov    rcx,QWORD PTR [rbp-0x28]
    1175:   48 8b 45 e0             mov    rax,QWORD PTR [rbp-0x20]
    1179:   48 8b 55 e8             mov    rdx,QWORD PTR [rbp-0x18]
    117d:   48 89 01                mov    QWORD PTR [rcx],rax
    1180:   48 89 51 08             mov    QWORD PTR [rcx+0x8],rdx
    1184:   48 8b 45 f0             mov    rax,QWORD PTR [rbp-0x10]
    1188:   48 8b 55 f8             mov    rdx,QWORD PTR [rbp-0x8]
    118c:   48 89 41 10             mov    QWORD PTR [rcx+0x10],rax
    1190:   48 89 51 18             mov    QWORD PTR [rcx+0x18],rdx
    1194:   48 8b 45 d8             mov    rax,QWORD PTR [rbp-0x28]
    1198:   5d                      pop    rbp
    1199:   c3                      ret

从反汇编来看,在调用函数之前,所需的空间已在堆栈上分配,函数会填充这些值。

但在第二部分中,rdi 似乎被视为指向 number 结构的指针,其中的值也被保存。这是关于什么的?

当在汇编程序中使用 C 函数时,我如何知道结果在哪里?

【问题讨论】:

  • 您可以在this question找到一些信息。
  • 参考您平台的ABI文档。对你来说,这似乎是 amd64 SysV ABI 的补充。
  • @jaklh 使用-O0 你告诉编译器关闭它的大脑并生成尽可能愚蠢的代码。在这种情况下,你为什么期望有好的代码?
  • 该代码比必要的更难遵循,因为您禁用了优化。通过优化,您只会看到存储到返回值对象中,而不是初始化本地 res。 (这就是 this 函数在堆栈上分配的空间。)godbolt.org/z/M79b6zqrP : gcc -O3 使用两个 SSE2 存储,gcc -O2 使用四个直接为 0 的 qword 存储。
  • 请注意,x86-64 System V 有据可查,Where is the x86-64 System V ABI documented?。在 RDX:RAX 或仅 RAX 中返回较小的结构(适合 16 个字节或更少)。 C++ on x86-64: when are structs/classes passed and returned in registers?

标签: c assembly x86-64 calling-convention


【解决方案1】:

调用约定通常不具体规定任何代码或代码序列,它只规定状态——例如寄存器和内存,用于参数传递和堆栈:参数和返回值去哪里,必须保存什么状态调用(即一些寄存器和分配的堆栈内存),以及什么是暂存(即一些寄存器和当前堆栈指针下方的内存)。它还可能规定诸如堆栈对齐要求之类的内容。

调用约定如上所述:但仅在非常特定的时间点,即控制从调用者转移到被调用者的确切边界,以及当控制从被调用者转移回调用者时再次发生。因此,被调用者期望调用者在其第一条指令运行之前已按预期设置所有参数。调用者期望被调用者在从调用中恢复的第一条指令之前已经设置了所有返回值(并保留了它必须保留的任何内容)。

出于这些目的,调用约定并不规定机器代码指令甚至指令序列;它只在转移点建立对价值和位置的期望。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 2014-04-22
    相关资源
    最近更新 更多