Where i开发者_开发问答n 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]
?
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.
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.
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.
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.
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.
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
精彩评论