Search code examples
cassemblyatt

how to get argument integer in callee?


I have the following code (caller.c):

#include <stdio.h>

extern int callee(int);

int main(int argc, char *argv[]){
  callee(4);
  return 1;
}

and (callee.s):

.globl callee

callee:
  pop %eax
  add $4, %eax
  ret

I compile with: gcc -m32 caller.c callee.s

and run:

./a.out

Segmentation fault (core dumped)

I am wondering what my mistake(s) is/are as I believed that main should now push a 32 bite number of the stack. I havent changed stack so that callee should now be able to pop that number from the same stack. Maybe I should add (add $4, %esp) before the pop (if the address of callee is in the "way"/actually been popped). I have tried that too with no success. callee should now get the number from the stack and add 4 to it. The eax-register should be where the return value from callee to caller should be kept (calling convention), but here I ignore the return value.

Could someone assist me?

related question: calling assembly function from c

calling convention: https://en.wikipedia.org/wiki/X86_calling_conventions


Solution

  • (With the x86-32 calling convention,) the arguments to a function are pushed on the stack first, and then the return address. Thus, your pop instruction popped the return address, and the subsequent ret tried to return to address 0x00000004, which is unmapped memory, causing a crash.

    Also, in this convention the callee is not supposed to pop its arguments. The caller will do that.

    The code you should have written is

    callee:
        movl 4(%esp), %eax
        addl $4, %eax
        ret
    

    You can confirm this for yourself by compiling

    unsigned int callee(unsigned int x) { return x + 4; }
    

    with the options -m32 -O2 -S -fomit-frame-pointer and inspecting the .s file produced; you should get the same assembly code as above.