内存中的返回值存储在内存中?

时间:2011-03-29 11:48:48

标签: low-level

内存中的返回值是存储在内存中的吗?

考虑以下代码:

int add(int a, int b) {
    int result = a+b;
    return result;
}

void main() {
    int sum = add(2, 3);
}

当调用add(2, 3)时,2个函数参数被压入堆栈,堆栈帧指针被压入堆栈,并且返回地址被压入堆栈。然后执行流程跳转到add(...),该函数中的局部变量也存储在堆栈中。

add(...)完成后,执行return指令...返回值存储在哪里? [result]如何以[sum]结束?

6 个答案:

答案 0 :(得分:5)

这显然取决于您的硬件架构和编译器。在使用gcc的64位x86上,您的代码将编译为:

        .file   "call.c"
        .text
.globl add
        .type   add, @function
add:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movl    %edi, -20(%rbp)
        movl    %esi, -24(%rbp)
        movl    -24(%rbp), %eax
        movl    -20(%rbp), %edx
        leal    (%rdx,%rax), %eax
        movl    %eax, -4(%rbp)
        movl    -4(%rbp), %eax      ; return value placed in EAX
        leave
        ret
        .cfi_endproc
.LFE0:
        .size   add, .-add
.globl main
        .type   main, @function
main:
.LFB1:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    $3, %esi
        movl    $2, %edi
        call    add
        movl    %eax, -4(%rbp)      ; the result of add is stored in sum
        leave
        ret
        .cfi_endproc
.LFE1:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
        .section        .note.GNU-stack,"",@progbits

这里,编译器使用EAX寄存器将add的结果传递给调用者。

您可以在Wikipedia中阅读x86调用约定。

答案 1 :(得分:5)

这个问题没有一般的答案,因为它取决于目标架构。对于任何定义该目标体系结构的目标体系结构,通常都有一个二进制API规范,并且编译器会创建根据此规范工作的代码。大多数架构使用寄存器来传回返回值,因为它是最快的方法。当然,只有当值适合寄存器时才有可能。如果不是,它们可能使用寄存器对(例如,一个寄存器中的低32位,另一个寄存器中的高32位),或者它们将通过堆栈将其传回。有些架构从不使用寄存器,总是通过堆栈传回。由于调用者必须在调用函数之前创建一个堆栈帧(此规则有例外,但让我们保留默认情况),当函数返回调用者并且调用者知道如何访问时,堆栈帧仍然存在它,它必须知道,因为它还必须在返回时清理堆栈帧。在大多数体系结构中,调用者清除堆栈帧而不是被调用者,因为调用者知道它通过栈传递了多少个参数(例如,对于一个接受可变数量参数的C函数),而被调用者则不知道(不是在编译时)时间,被调用者可能只知道在运行时),因此让调用者清理它更有意义。在此之前,调用者可以回读它希望检索的堆栈帧的任何值。

答案 2 :(得分:4)

在x86上,返回值放在EAX寄存器中(可能取决于你的实际调用约定)。

您可以反汇编从源代码编译的代码,以检查确实会发生什么。

答案 3 :(得分:0)

函数参数,局部变量和返回值可以在堆栈中推送/弹出,或者存储在内部CPU寄存器中,它与系统高度相关。

答案 4 :(得分:0)

通常在累加器中。对于不适合累加器的返回值,累加器将在堆栈上保存指向它的指针。这是一个常见的方案,在我在该级别处理的几个平台上使用,但依赖于硬件,我也想在编译器/汇编器上。

答案 5 :(得分:0)

EAX用于存储返回值(如果大小允许)(此处可以);它是调用者的动作(主要在你的情况下)将EAX内容分配给总和