Search code examples
assemblyx86-64return-valueattfunction-call

How do function calls return a value in x86-64 assembly?


Say I have a function foo defined as:

def foo(x,y):
  return x + y

and say I have function call:

foo(2,3)

which corresponds to the x86-64:

movq $2 %rdi
movq $3 %rsi
call foo

I am aware that if the function foo has a return value it will be stored in the register %rax. but what does this mean exactly?

the assembly would be something like:

movq $2 %rdi
movq $3 %rsi
call foo

foo:
    movq -8(%rsb) %rax
    addq -16(%rsb) %rax

can you please finish the definition of foo in assembly? does it use %rax? how does it use %rax?

My question is how %rax is used to get the return value of a function and how this value in %rax gets passed between the caller and callee. thanks


Solution

  • Just to illustrate how this works, I'll use your function foo as an example:

    def foo(x,y):
      return x + y
    
    main:
       z = foo(7,10) * 3
    

    So here's how the value of z would be calculated. (Chances are what would actually happen is that the compiler would just precalculate 17*3 and load it as a constant, but that's not helpful for what I'm trying to demonstrate.)

    main:
      mov  $7, %edi       # put integer args in 64-bit registers efficiently
      mov  $10, %esi      # with zero-extension of 32-bit
      call foo      
    
    #the ret instruction at the end of "foo" takes us back here
    #the result of "foo" is now in %rax, and the rest of the program can use it.
    
      mov %rax, %rdx    # Save a copy of %rax so we can multiply by 3.
      shl $1, %rax      # multiply by 2
      add %rdx, %rax    # add the original, this means we effectively multiplied by 3.
    
    # lea (%rax, %rax, 2), %rax   # efficient way to multiply by 3
    
      ret              # exit program by returning from main()
    
    ####################################################
    
    foo:
      add %rsi, %rdi    # add the two numbers
      mov %rsi, %rax    # return value in %rax
      ret
    
    # compilers would have used  lea (%rdi, %rsi), %rax  to copy-and-add