20.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 14.2 Register Conventions. In particular, registers $4-$7 are used for parameter passing. An assembly -language function will receive parameters, and should pass arguments to called functions, in these registers.
- Table 14-1 describes which registers must be saved across non-interrupt function calls.
- 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
. 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.S
*/
#include <xc.h>
/* define which section (for example "text")
* does this portion of code resides in. Typically,
* all your code will reside in .text section as
* shown below.
*/
.text
/* This is important for an assembly programmer. This
* directive tells the assembler that don't optimize
* the order of the instructions as well as don't insert
* 'nop' instructions after jumps and branches.
*/
.set noreorder
/*********************************************************************
* asmFunction(int bits)
* This function clears the specified bites in IOPORT A.
********************************************************************/
.global asmFunction
.ent asmFunction
asmFunction:
/* function prologue - save registers used in this function
* on stack and adjust stack-pointer
*/
addiu sp, sp, -4
sw s0, 0(sp)
la s0, LATACLR
sw a0, 0(s0) /* clear specified bits */
la s0, PORTA
lw s1, 0(s0)
la s0, cVariable
sw s1, 0(s0) /* keep a copy */
/* function epilogue - restore registers used in this function
* from stack and adjust stack-pointer
*/
lw s0, 0(sp)
addiu sp, sp,
addu s1, ra, zero
jal foo
nop
addu ra, s1, zero
nop
/* return to caller */
jr ra
nop
.end asmFunction
.bss
.global asmVariable
.align 2
asmVariable: .space 4
The file ex1.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.c
*/
#include <xc.h>
extern void asmFunction(int bits);
extern unsigned int asmVariable;
volatile unsigned int cVariable = 0;
volatile unsigned int jak = 0;
int
main(void) {
TRISA = 0;
LATA = 0xC6FFul;
asmFunction(0xA55Au);
while (1) {
asmVariable++;
}
}
void
foo(void) {
jak++;
}
In the C file, ex2.c
, external references to symbols
declared in an assembly file are declared using the standard extern
keyword; note that asmFunction
is a void
function
and is declared accordingly.
In the assembly file, ex1.S
, the symbols
asmFunction
and asmVariable
are made globally
visible through the use of the .global
assembler directive and can
be accessed by any other source file.