x86 Assembly: Calling Conventions

CS 301 Lecture, Dr. Lawlor, 2005/10/03

Example of Local Variables

Here's an example where we set up a stack frame (using %ebp as a frame pointer) with room for 4 integers, and use two of the local variable slots to store two integers read in from a file.   Note that because calling a subroutine may trash %eax, %ebx (if not position-independent), %ecx, and %edx, you can't store the value in any of these registers!
push %ebp  # Prologue
mov %esp,%ebp
sub $16,%esp # Make room for 4 4-byte ints

call read_input # Read A
mov %eax,-4(%ebp) # Store A into -4(%ebp)
call read_input # Read B
mov %eax,-8(%ebp) # Store B into -8(%ebp)

add -4(%ebp),%eax # A+B
push %eax # Print the value in %eax
call print_int
pop %ebx # Clean stack

mov %ebp,%esp # Epilogue
pop %ebp # (these two lines=="leave")

Calling Conventions

SysV ABI (Page 35-43) / win32 "cdecl"
Win32 "stdcall":
Win32 "fastcall":

Non-Lecture Bonus Material

Raw machine code: .byte

With UNIX assembly, you can add plain machine code bytes with the ".byte" command, like this:
    .byte 0xb8, 0x0d, 0xd0, 0,0 # == mov <const>, %eax
    .byte 0xc3 #  == ret
You can get the machine code from the disassembly.  Try it!

Enter Instruction

The x86 "enter stack_size, nesting" instruction can be used at the start of a subroutine to set up a stack frame.  "stack_size" is the number of bytes of stack space to leave for local variables.  "nesting" is used for nested procedures (which don't exist in C!), so it's normally 0.  So an "enter $16,$0" call is exactly equivalent to the standard three-line function prologue above:
push %ebp  # Prologue
mov %esp,%ebp
sub $16,%esp # Make room for 4 4-byte ints
This means "enter" is the exact analogue of "leave".  I think I'll keep using the push/mov/sub, just because that way it's clearer exactly what happens.