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