UMBC CMSC 313 -- Assembly Language File Previous | Next


Assembly Language File

Before

Remember what the function looks like.

int func( int a, int b, int c )
{
  return a + b + c;
}

  

After

We are going to convert this, so that func( ) is a assembly language subprogram. There are no global variables in this subprogram. Actually, there are no global variables in the entire program. There are three parameters of the built-in int datatype, 4 bytes each.

Work Done by the Calling Function

The calling function will put the parameters on the stack, starting on the right side of the list. This means that when main( ) calls func, the first parameter to be pushed is c, followed by b, and finally a. Then the return address will be put on the stack and control is transferred to func( ).

The Code

Put into assembly language, we get:
        section .data
        section .bss

	section .text
        global  func
func:
	push	ebp
	mov	ebp, esp
	mov	eax, [ ebp + 8  ]     ; get a
	add	eax, [ ebp + 12 ]     ; add b
	add	eax, [ ebp + 16 ]     ; add c
	mov	esp, ebp
        pop     ebp

	ret

  

The Program In Execution

By using the debugger, we can run up to the call to our function and stop at the statement,

w = func( x, y, z );

Analysis

Since the parameters and the return addresses are all 32-bit (4 byte) values, when the call is executed, the parameters are pushed on to the stack from left to right and the return address is pushed on the stack, which grows downward. When the function is called we will see the stack as:
stack
pointer
stack
contents
 c
 b
 a
esp->return address

OK, that looks good. Now, we have to get to things and the esp register might change, so we will use the ebp register to help us. Save it first by pushing it on to the stack (push ebp):

stack
pointer
stack
contents
 c
 b
 a
 return address
esp->ebp

Make the ebp register point to what the esp register points to (mov ebp, esp), that way, if the esp register changes, it does not affect how we point to the parameters. To see the acual values in a sample run, we use the debugger and get:

stack
pointer
stack
contents
offset
 c: 0x00000003ebp+16
 b: 0x00000002ebp+12
 a: 0x00000001ebp+8
 return address: 0x08048366ebp+4
ebp->old ebp: 0xbfffea28old ebp

Concerning the contents, the names a, b, and c represent what I had used in the C version of func( ). The return address point to the statement:

printf( "%d\n", w ); The actual address can vary with each execution, as this is controlled by the operating system, and the 0xbfffea28 in the old ebp will also depend on the operating system and can vary with each execution.

After the return value has been calculated, it is necessary to restore the ebp register and perform a return instruction (ret).

Returning A Value To The Calling Function

It is not shown here in an obvious way how the value is returned to the calling function and what happens to the stack when the control is passed back to the main( ) function in C. Simple!

Whatever is in the eax register is moved to the specified location, in this case, the variable w, with something like (if it were in assembly language):

mov dword [ w ], eax Then the stack must be cleaned up with a statement such as: add esp, 12         ; 3 variables @ four bytes each.

Now the C program can continue along its merry way. Life is good.


©2005, Gary L. Burt

Previous | Next