UPDATE: Part II is ready.

In my current job I often need to write instructions in assembly. It’s usually an one-line instruction so I simply embed it in C using inline asm. But when I need to write more than an one-line code I would prefer to write them directly in assembly.

Is that difficult?

Function is a sequence of instructions grouped in a logical sense to perform a particular task, they are abstractions implemented by the programming language. The code generated by compilers make use of labels and jumps, stack and registers. So, you basically need to do the job that your compiler does to you. It’s not difficult but requires some extra work, for instance:

    cat function.S
    .align 2
    .type my_function,@function;
    .globl my_function;
    my_function:
        blr
  • .align 2 - section is 2-byte aligned.
  • .type my_function,@function - useful for debugging, not required.
  • .globl my_funcion - “my_function” is available outside from this unit.
  • my_function: - label.
  • blr - PowerPC instruction that branches unconditionally to the address stored in Link Register.
    $ cat function.c
    #include <stdio.h>
    
    /*
     * I'm telling to C compiler that my_function expects and returns an integer.
     * I'm also making a promise: the implementation will be available later.
     */
    extern int my_function(int param);
    
    int main(void)
    {
        int i = my_function(5);
        printf("%d\n", i);
        return 0;
    }
    $ gcc -g3 function.S function.c -o function
    $ ./function
    5

Isn’t it cool? I just wrote a “function” in assembly that does nothing more than returning the same value used as parameter. Magic? No, and we will see why.

Application Binary Interface - ABI

To write a compliant C function we need to respect some rules (the same rules that the C compiler respects when it generates the binary code). These rules are defined by the ABI, or Application Binary Interface, that is tied to the target architecture.

About function, it defines rules like: where parameters are a expected to be, how to set up your stack frame, where to store the return values, etc. Those rules help to organize the system in a way that multiple languages can interact with each other (calling libraries, for instance) without problems.

The following interactive animation illustrates an imaginary toy processor and how functions work within its simple specification: 3 registers and some memory. This is the code that would be generated by a C compiler for that imaginary target.

    int x = mult(5, 3);
    printf("%d", x);
    int y = mult(x, 2);
    printf("%d", y);

Note: click ‘n’ to go to the next instruction, this is a simple (but real) virtual machine.