My comments are tagged with the C comment characters.
.file "fCall.c" // the original source file
.def ___main; .scl 2; .type 32; .endef
.text // this goes into the text segment
LC0: // a gnerated label to store the string value
.ascii "hello\0" // note that the string goes into TEXT segment!
.align 2 // tells linker to align this section on a two byte border
.globl _main // puts our main in the .global section
.def _main; .scl 2; .type 32; .endef
_main: // this is where our main really starts
pushl %ebp // save frame (base) pointer on stack
movl %esp, %ebp // store stackpointer in framepointer
subl $24, %esp // decrement stack pointer to make room
// for main's local variables and future call arguments
andl $-16, %esp
movl $0, %eax // put 0 into eax register
movl %eax, -16(%ebp) // move content of eax to where framepointer points
// but with offset -16
movl -16(%ebp), %eax // get framepointer offset -16 into eax ???
call __alloca // call a c-runtime function to allocate memory
call ___main // call a c-runtime function __main
movl $LC0, -4(%ebp) // get the address of LC0 (our string) and put it to
// framepointer -4 on the stack. This is not surprisingly
// where our first local variable "string" lives.
movl $0, -8(%ebp) // put a 8 at framepointer -8 where our second var lives
// (result)
movl $1, -12(%ebp) // put 1 at framepointer -12 where our third var (arg1)lives
movl -12(%ebp), %eax// move arg1 from stack into register eax
movl %eax, (%esp) // put eax content on stack. Note, this is the leftmost
// argument for function call!!!
movl -4(%ebp), %eax // put the string address from stack into eax
movl %eax, 4(%esp) // and put it from there onto the stack
// now we have set up the stack with two arguments and can
// call our function.
// You will need to look at _myFunc to see how the arguments
// are processed by our function.
call _myFunc // tell CPU to push the current instruction address on the
// stack (saving it for return) and move the address where
// _myFunc lives into the instruction register
//----------------------------------------------------
// after we come back from the call to _myFunc:
movl %eax, -8(%ebp) // in eax is the return value from our function call
// with a debugger you would find 44 here
movl $0, %eax // generate main's return value (0 for everything OK)
leave // restore framepointer and stackpointer to how they
// where BEFORE main function was running
ret // tell CPU to get return address (the address from where
// our main was called) and jump to it, effectively continuing
// callers processing right after the function call to main.
// in this case this would mean jumping back into the
// C-runtime code which started our program.
//-----------------------------------------------------
.align 2
.globl _myFunc
.def _myFunc; .scl 2; .type 32; .endef
myFunc:
pushl %ebp //save framepointer from caller (prolog)
movl %esp, %ebp // put stackpointer into framepointer which
// is now our vehicle to access OUR (myFunc's) local
// variables and arguments
subl $8, %esp // make room on stack for 8 bytes
movl 8(%ebp), %eax // move 4 bytes from framepointer offset 8 into eax register
movl %eax, -4(%ebp) // move those bytes now into local variable at offset -4
// what does: int localVar = intPar;
movl 12(%ebp), %eax // again move 4 bytes from offset 12 into eax
movl %eax, -8(%ebp) // and store them at offset -8 which makes:
// char* localString = stringPar;
movl $44, %eax // put decimal 44 into register eax which
// creates our RETURN value (must be in eax as we
// will see when we look at how the caller receives this
// value: return 44;
leave // clean up the local calling frame (restore framepointer and
// stack pointer to HOW THE CALLER LEFT THEM. Any surprise here
// is not really funny.
ret // tells the cpu to take the callers return address from stack
// into the instruction pointer register and continue executing