17.1 Mixing Assembly Language and C/C++ Variables and Functions
The following guidelines indicate how to interface separate assembly language modules with C/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 ensure that all registers are preserved. 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/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/C++ functionmainis named_mainin assembly and conversely an assembly symbol_do_somethingwill be referenced in C/C++ asdo_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/C++ regardless of where they were originally defined.
The file ex1.h declares asmVariable,
asmFunction and foo and for C++ adds extern
"C" to prevent name mangling when linking with assembly.
The file ex1.c (or ex1.cpp) defines
cVariable and foo to be used in the assembly language file.
The C/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.h
*/
#ifdef __cplusplus
extern "C" {
#endif
extern unsigned int asmVariable;
void asmFunction(void);
void foo(void);
#ifdef __cplusplus
}
#endif
/*
** file: ex1.c (or ex1.cpp)
*/
#include "ex1.h"
volatile 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
.endIn the C/C++ file, 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 incall2.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
.endParameter 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.
