Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where in memory are return values stored in memory?

Tags:

low-level

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]?

like image 782
Richard JP Le Guen Avatar asked Mar 29 '11 11:03

Richard JP Le Guen


People also ask

Where in memory are functions stored?

The short answer: It will be stored in the text or code section of the binary only once irrespective of the number of instances of the class created.

How are variable stored in memory?

Variables are usually stored in RAM. This is either on the heap (e.g. all global variables will usually go there) or on the stack (all variables declared within a method/function usually go there). Stack and Heap are both RAM, just different locations.

Where are method parameters stored in Java?

The actual method is stored in the Method Area. Parameters, return values, local variables,... are stored within a Method Frame, which in return resides on the Stack.

Where are global variables stored in C?

Global variables are stored in the data section.


2 Answers

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.

like image 170
NPE Avatar answered Sep 16 '22 23:09

NPE


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.

like image 26
Mecki Avatar answered Sep 16 '22 23:09

Mecki