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 Register Conventions. In particular, registers r0-r3 are used for parameter passing. An assembly language function will receive parameters, and should pass arguments to called functions, in these registers.
 - The table in Register Conventions 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 cFunction 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
      .syntax unified
      .cpu cortex-m7
      .thumb
      .global asmVariable
      .type asmVariable,%object
      .data
      .align 2
asmVariable:
      .space 4
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      @ char *asmFunction (char *s)
      @ {
      @    asmVariable = 0;
      @    if (s) {
      @       char *d = s, c;
      @       while ((c = *d)) {
      @         if (cFunction (c)) {
      @          *d = c & cVariable;
      @          ++asmVariable;
      @       }
      @       ++d;
      @      }
      @    }
      @    return s;
      @ }
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      .global asmFunction
      .type asmFunction,%function
      .text
      .align 1
      .thumb_func
asmFunction:
      @ if the input string is not NULL
      cbnz r0, .L_not_NULL
      @ set 'asmVariable' to zero and return
      ldr    r1, =asmVariable
      str    r0, [r1]
      bx     lr
.L_not_NULL:
      @ r4-r7 are callee-saved registers
      @ LR contains the return address
      @ r0 is the first argument and also the return value of the
function
      push {r0, r4-r7, lr}
      @ d = s;
      mov r4, r0
      @ r6 - the value of the C variable (8-bit AND mask)
      @ r7 - counter of changed chars
      ldr     r6, =cVariable
      movs    r7, #0
      ldrb    r6, [r6]
.L_while:
      @ while ((c = *d))
      ldrb r5, [r4]
      cbz r5, .L_end_while
      @ if (cFunction (c))
      mov   r0, r5
      bl    cFunction
      cbz r0, .L_next_char
      @ *d = c & cVariable;
      ands r5, r5, r6
      strb r5, [r4]
      @ ++ the number of changed chars
      adds r7, r7, #1
.L_next_char:
      @ ++d;
      adds r4, r4, #1
      b .L_while
.L_end_while:
      @ write the no. of changes to 'asmVariable'
      ldr    r0, =asmVariable
      str    r7, [r0]
      @ return s;
      pop {r0, r4-r7, pc}
      .pool
      .size asmFunction, .-asmFunction
         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, cFunction, and how
            to access a C defined variable, cVariable.
#include <xc.h>
#include <stdio.h>
extern int asmVariable;
extern char *asmFunction (char *s);
char cVariable = 0xDF;
char cFunction (char c)
{
   return c >= 'a' && c <= 'z';
}
int main()
{
   char s[] = "heLLo, wOrlD!";
   printf ("%s\n", s);
   char *d = asmFunction (s);
   printf ("%s\nchanges: %d", d, asmVariable);
   return 0;
}
         In the C file, ex2.c, although for the function
            declaration this isn’t required, note that asmFunction is a
               char * 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.
