3

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

Community
  • 1
  • 1
stian
  • 1,947
  • 5
  • 25
  • 47
  • 1
    This fails because your `pop %eax` takes the return address pushed by the _CALL_ instruction and puts in in _EAX_. Remove the `pop %eax` and simply access the first argument via `mov 4(%esp), %eax`. After execution is transferred to a function (in 32-bit code) the return address is at 0(ESP), first argument at 4(ESP), second argument at 8(ESP) etc. – Michael Petch Apr 18 '17 at 15:15
  • To return an int from a function, load it into `eax` (however, check the specifics of your platform/compiler). – Paul Ogilvie Apr 18 '17 at 15:22

1 Answers1

4

(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.

zwol
  • 135,547
  • 38
  • 252
  • 361