Where in memory are return values stored in memory?

我只是一个虾纸丫 提交于 2019-12-23 12:29:21

问题


Where in memory are return values stored in memory?

Consider the follwing code:

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

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

When add(2, 3) is called, the 2 function parameters are pushed on the stack, the stack frame pointer is pushed on the stack, and a return address is pushed on the stack. The flow of execution then jumps to add(...), and local variables within that function are also stored on the stack.

When add(...) is complete, and executes the return instruction... where does the return value get stored? How does [result] end up in [sum]?


回答1:


This clearly depends on your hardware architecture and your compiler. On 64-bit x86 using gcc, your code compiles to:

        .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

Here, the compiler is using the EAX register to communicate the result of add to the caller.

You can read up on x86 calling conventions in Wikipedia.




回答2:


There is no general answer to this question, because it depends on the target architecture. There is usually a Binary API Spec for any target architecture that defines that and the compiler creates codes that works according to this spec. Most architectures use a register for passing the return value back, simply because it is the fastest way to do it. That is only possible if the value will fit into a register, of course. If not, they might use a register pair (e.g. lower 32 bit in one register, upper 32 bit in another one), or they will pass it back via the stack. Some architectures never use registers and always pass back via the stack. Since the caller must create a stack frame before calling the function (there are exceptions to this rule, but lets stay with the default case here), the stack frame is still there when the function returns to the caller and the caller knows how to access it, it has to know that, since it must also clean the stack frame on return. On most architectures the caller cleans the stack frame, not the callee, since the caller knows how many arguments it has passed via stack (e.g. for a C function that takes a variable number of arguments), while the callee does not (not at compile time, the callee may only know that at runtime), thus it makes more sense to let the caller clean it. And before doing that, the caller can read back any value of the stack frame it wishes to retrieve.




回答3:


On x86 the return value is put in the EAX register (that may depend on your actual calling convention though).

You could disassemble the code compiled from your source to check what happens for sure.




回答4:


The function parameters, local variables and return values may be pushed/popped on the stack, or be stored into internal CPU registers, it is highly system dependent.




回答5:


Usually in the accumulator. For a return value that does not fit into the accumulator, the accumulator will hold a pointer to it on the stack. This is a common scheme, used on the few platforms I have dealt with at that level, but depends on hardware and I think on the compiler/assembler too.




回答6:


EAX is used to store the return value if the size permits it (here it does); it's the caller's action (main in your case) to assign the EAX content to sum



来源:https://stackoverflow.com/questions/5472008/where-in-memory-are-return-values-stored-in-memory

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!