Calling An Asm Function From C

Calling functions written in assembly from C is not so difficult, but it is important you understand the C function calling convention. According to this convention parameters are to be pushed onto the stack and return values stored in the eax register.

This means that when we call our function from C, the C compiler will push the parameters onto the stack, and our asm program must look there to fetch them.

But where exactly on the stack are they stored? To answer this we must first know what the stack looks like on entering our asm function.

When we invoke our function the C compiler does the following:

(1) Pushes all the parameters for the function onto the stack, in reverse order to their order in the function prototype. Why reverse order? So that the first parameter popped off the stack matches the first (left-most) parameter declared in the C function prototype.

(2) Pushes the return address for the function onto the stack. The return address is the address of the next instruction in the calling function, it is where execution takes off once the asm function has completed.

Inside our asm function the following should also be performed on entry: (the function prologue)

(1) The ebp (base pointer/frame pointer) register is pushed onto the stack.
(2) The esp (stack pointer) register is saved to the ebp register.

The stack-related operations therefore are the pushing of parameters, the pushing of the return address and the pushing of the base pointer.

After these operations the stack will look like this:

------top of stack------
*old ebp
*return_address
*parameter 1
*parameter 2
.....
*parameter N
.....
-------------------------

We can now see where on the stack the parameters are stored and can access them easily enough. Since every element on the stack in our example is 4 bytes long we can find  the first parameter by adding 8 to the address of ebp and then using indirection to get the value stored there. Why do we add 8 ? Because we need to skip over the old ebp (4 bytes) and the return address (also 4 bytes).

Expressed in at&t assembly notation we get the first parameter by doing the following:

(and saving it into the eax register):

movl 8(%ebp), %eax

The address of the second parameter is also found by adding 12 to the base pointer address (we are assuming that each parameter is 4 bytes).

In my example code that follows the C function is passing two parameters to the asm function; the first being a pointer to the start of an integer array; the second parameter being the size of that array.

Here is the code:

#include <stdio.h>

/* prototype for asm function */
int * asm_mod_array(int *ptr,int size);

int
main() {
int fren[5]={ 1, 2, 3, 4, 5 };

/* call the asm function */
asm_mod_array(fren, 5);

return 0;
}

Note prototyping and calling an asm function is the same as with a regular C function.

Now here is the code for the asm function:


#VARIABLES: The registers have the following uses:
# description: this function takes an int array and multiplies
#              every element by 2 and adds 5.
# %edi - Holds the index of the data item being examined
# %ecx - size of the array
# %eax - pointer to first item in array
# %edx - used for scratch space
#
.section .text
.globl asm_mod_array
.type asm_mod_array, @function
asm_mod_array:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp),%eax          # get pointer to start of array passed from C
movl 12(%ebp),%ecx         # get size of array
xorl %edi, %edi            # zero out our array index

start_loop:                # start loop
cmpl %edi, %ecx            # check to see if we’ve hit the end
je loop_exit
movl (%eax,%edi,4), %edx   # store the element in %edx for calculations
leal 5(,%edx,2), %edx      # multiply array element by 2 and add 5
movl %edx, (%eax,%edi,4)   # overwrite old element with new value
incl %edi                  # increment the index, moving through the array.
jmp start_loop             # jump to loop beginning

loop_exit:                 # function epilogue
movl %ebp, %esp
popl %ebp
ret                        # pop the return address and jmp to it

We do not modify the eax register after we copy the pointer into it, so the return value of the asm function (in accordance with the C function calling convention) will be the pointer.

These programs both compile on a 32 bit linux system using ‘as’ and ‘gcc’. To use simply compile each program to a .o (object file) and then link them together using gcc -o.

Tags: ,

3 Comments to “Calling An Asm Function From C”

  1. All this asm stuff is all very well, but when I hack the mainframe my weapon of choice is the bitchX OpenGL assembly hacker suite. It suits my needs and also comes with a free 3-D fruit peeler.

    Do you prefer linux or microsoft internet safari for your web-browsing mainstay? next time I dont use youtube, I probably won’t even consider facebook as a viable back-end neural-network module, I’d rather just buy a pack of band-aides, a McFlurry and a big bag of balloons. Life, like truth, like hacking, is all about hitting that Bitch in X marks the spot.

    Tricksy.

  2. Your blog is interesting!

    Keep up the good work!

Leave a comment