17.1 Mixing Assembly Language and C Variables and Functions

The following guidelines indicate how to interface separate assembly language modules with C modules.

  • Follow the register conventions described in 13.1 Register Variables. In particular, registers W0-W7 are used for parameter passing. An assembly language function will receive parameters and pass arguments to called functions in these registers.
  • Functions not called during interrupt handling must preserve registers W8-W15. That is, the values in these registers must be saved before they are modified and restored before returning to the calling function. Registers W0-W7 may be used without restoring their values.
  • Interrupt functions must preserve all registers. Unlike a normal function call, an interrupt may occur at any point during the execution of a program. When returning to the normal program, all registers must be as they were before the interrupt occurred.
  • Variables or functions declared within a separate assembly file that will be referenced by any C source file should be declared as global using the assembler directive .global. External symbols should be preceded by at least one underscore. The C function main is named _main in assembly and conversely an assembly symbol _do_something will be referenced in C as do_something. Undeclared symbols used in assembly files will be treated as externally defined.

The following example shows how to use variables and functions in both assembly language and C regardless of where they were originally defined.

The file ex1.c defines foo and cVariable to be used in the assembly language file. The C file also shows how to call an assembly function, asmFunction, and how to access the assembly defined variable, asmVariable.

Mixing C and Assembly

/*
** file: ex1.c
*/
extern unsigned int asmVariable;
extern void asmFunction(void);
unsigned int cVariable;

void foo(void)
{
 asmFunction();
 asmVariable = 0x1234;
}

The file ex2.s defines asmFunction and asmVariable as required for use in a linked application. The assembly file also shows how to call a C function, foo, and how to access a C defined variable, cVariable.

;
; file: ex2.s
;
 .text
 .global _asmFunction
_asmFunction:
 mov #0,w0
 mov w0,_cVariable
 return
 .global _main

_main:
 call _foo
 return
 .bss
 .global _asmVariable
 .align 2

_asmVariable: .space 2
 .end

In the C file, ex1.c, external references to symbols declared in an assembly file are declared using the standard extern keyword; note that asmFunction, or _asmFunction in the assembly source, is a void function and is declared accordingly.

In the assembly file, ex1.s, the symbols _asmFunction, _main and _asmVariable are made globally visible through the use of the .global assembler directive and can be accessed by any other source file. The symbol _main is only referenced and not declared; therefore, the assembler takes this to be an external reference.

Calling an Assembly Function in C

The following compiler example shows how to call an assembly function with two parameters. The C function main in call1.c calls the asmFunction in call2.s with two parameters.

/*
** file: call1.c
*/
extern int asmFunction(int, int);
int x;

void main(void)
{
  x = asmFunction(0x100, 0x200);
}

The assembly-language function sums its two parameters and returns the result.

;
; file: call2.s
;
 .global _asmFunction
_asmFunction:
 add w0,w1,w0
 return
 .end

Parameter passing in C is detailed in 14.7.2 Return Value. The two integer arguments are passed in the W0 and W1 registers. The integer return result is transferred via register W0. More complicated parameter lists may require different registers and care should be taken in the hand-written assembly to follow the guidelines.