4.4.3. Examples of calling between languages

The following sections contain code examples that demonstrate how to mix language calls:

Calling assembly language from C

Example 4.4 and Example 4.5 show a C program that uses a call to an assembly language subroutine to copy one string over the top of another string.

Example 4.4. Calling assembly language from C

#include <stdio.h>
extern void strcopy(char *d, const char *s);
int main()
{   const char *srcstr = "First string - source ";
    char dststr[] = "Second string - destination ";
/* dststr is an array since we’re going to change it */
    printf("Before copying:\n");
    printf("  %s\n  %s\n",srcstr,dststr);
    strcopy(dststr,srcstr);
    printf("After copying:\n");
    printf("  %s\n  %s\n",srcstr,dststr);
    return (0);
}

Example 4.5. Assembly language string copy subroutine

    PRESERVE8
    AREA    SCopy, CODE, READONLY
    EXPORT strcopy
strcopy               ; R0 points to destination string.
                      ; R1 points to source string.
    LDRB R2, [R1],#1  ; Load byte and update address.
    STRB R2, [R0],#1  ; Store byte and update address.
    CMP  R2, #0       ; Check for null terminator.
    BNE  strcopy      ; Keep going if not.
    BX   lr           ; Return.
    END

Example 4.4 is located in the examples directory, in ...\asm as strtest.c and scopy.s.

Follow these steps to build the example from the command line:

  1. Type armasm --debug scopy.s to build the assembly language source.

  2. Type armcc -c --debug strtest.c to build the C source.

  3. Type armlink strtest.o scopy.o -o strtest to link the object files.

  4. Run the image using a compatible debugger with an appropriate debug target.

Calling C from assembly language

Example 4.6 and Example 4.7 show how to call C from assembly language.

Example 4.6. Defining the function in C

int g(int a, int b, int c, int d, int e) 
{
    return a + b + c + d + e;
}

Example 4.7. Assembly language call

    ; int f(int i) { return g(i, 2*i, 3*i, 4*i, 5*i); }
    PRESERVE8
    EXPORT f
    AREA f, CODE, READONLY
    IMPORT g           ; i is in R0
    STR lr, [sp, #-4]! ; preserve lr
    ADD R1, R0, R0     ; compute 2*i (2nd param)
    ADD R2, R1, R0     ; compute 3*i (3rd param)
    ADD R3, R1, R2     ; compute 5*i
    STR R3, [sp, #-4]! ; 5th param on stack
    ADD R3, R1, R1     ; compute 4*i (4th param)
    BL g               ; branch to C function
    ADD sp, sp, #4     ; remove 5th param
    LDR pc, [sp], #4   ; return
    END

Calling C from C++

Example 4.8 and Example 4.9 show how to call C from C++.

Example 4.8. Calling a C function from C++

struct S {            // has no base classes 
                      // or virtual functions
    S(int s) : i(s) { }
    int i;
};
extern "C" void cfunc(S *); 
// declare the C function to be called from C++
int f(){
    S s(2);           // initialize 's'
    cfunc(&s);        // call 'cfunc' so it can change 's'
    return s.i * 3;
}

Example 4.9. Defining the function in C

struct S {
    int i;
};
void cfunc(struct S *p) {
/* the definition of the C function to be called from C++ */
    p->i += 5;
}

Calling assembly language from C++

Example 4.10 and Example 4.11 show how to call assembly language from C++.

Example 4.10. Calling assembly language from C++

struct S {        // has no base classes
                  // or virtual functions
    S(int s) : i(s) { }
    int i;
};
extern "C" void asmfunc(S *);   // declare the Asm function
                                // to be called
int f() {
    S s(2);                     // initialize 's'
    asmfunc(&s);                // call 'asmfunc' so it
                                // can change 's'
    return s.i * 3;
}

Example 4.11. Defining the assembly language function

    PRESERVE8
    AREA Asm, CODE
    EXPORT asmfunc
asmfunc                ; the definition of the Asm
    LDR R1, [R0]       ; function to be called from C++
    ADD R1, R1, #5
    STR R1, [R0]
    BX  lr
    END

Calling C++ from C

Example 4.12 and Example 4.13 show how to call C++ from C.

Example 4.12. Defining the function to be called in C++

struct S {        // has no base classes or virtual functions
    S(int s) : i(s) { }
    int i;
};
extern "C" void cppfunc(S *p) {    
// Definition of the C++ function to be called from C.
// The function is written in C++, only the linkage is C.
    p->i += 5;
} 

Example 4.13. Declaring and calling the function in C

struct S {
    int i;
};
extern void cppfunc(struct S *p); 
/* Declaration of the C++ function to be called from C */
int f(void) {
    struct S s;
    s.i = 2;                /* initialize 's' */
    cppfunc(&s);            /* call 'cppfunc' so it */
                            /* can change 's' */
    return s.i * 3;
}

Calling C++ from assembly language

Example 4.14 and Example 4.15 show how to call C++ from assembly language.

Example 4.14. Defining the function to be called in C++

struct S {           // has no base classes or virtual functions
    S(int s) : i(s) { }
    int i;
};
extern "C" void cppfunc(S * p) {
// Definition of the C++ function to be called from ASM.
// The body is C++, only the linkage is C.
    p->i += 5;
}

In ARM assembly language, import the name of the C++ function and use a Branch with Link (BL) instruction to call it:

Example 4.15. Defining assembly language function

    AREA Asm, CODE
    IMPORT cppfunc         ; import the name of the C++
                           ; function to be called from Asm
    EXPORT   f
f
    STMFD  sp!,{lr}
    MOV    R0,#2
    STR    R0,[sp,#-4]!    ; initialize struct
    MOV    R0,sp           ; argument is pointer to struct
    BL     cppfunc         ; call 'cppfunc' so it can change the struct
    LDR    R0, [sp], #4
    ADD    R0, R0, R0,LSL #1
    LDMFD  sp!,{pc}
    END

Passing a reference between C and C++

Example 4.16 and Example 4.17 show how to pass a reference between C and C++.

Example 4.16. Defining the C++ function

extern "C" int cfunc(const int&); 
// Declaration of the C function to be called from C++
extern "C" int cppfunc(const int& r) {
// Definition of the C++ function to be called from C.
    return 7 * r;
}
int f() {
    int i = 3;
    return cfunc(i);    // passes a pointer to 'i'
}

Example 4.17. Defining the C function

extern int cppfunc(const int*);    
/* declaration of the C++ function to be called from C */
int cfunc(const int *p) {       
/* definition of the C function to be called from C++ */
    int k = *p + 4;
    return cppfunc(&k);
}

Calling C++ from C or assembly language

The code in Example 4.18, Example 4.19 and Example 4.20 demonstrates how to call a non static, non virtual C++ member function from C or assembly language. Use the assembler output from the compiler to locate the mangled name of the function.

Example 4.18. Calling a C++ member function

struct T {
    T(int i) : t(i) { }
    int t;
    int f(int i);
};
int T::f(int i) { return i + t; }   
// Definition of the C++ function to be called from C.
extern "C" int cfunc(T*);    
// Declaration of the C function to be called from C++.
int f() {
    T t(5);                    // create an object of type T
    return cfunc(&t);
}

Example 4.19. Defining the C function

struct T;
extern int _ZN1T1fEi(struct T*, int);
    /* the mangled name of the C++ */
    /* function to be called */
int cfunc(struct T* t) {   
/* Definition of the C function to be called from C++. */
    return 3 * _ZN1T1fEi(t, 2);    /* like '3 * t->f(2)' */
}

Example 4.20. Implementing the function in assembly language

    EXPORT cfunc
    AREA foo, CODE
    IMPORT  _ZN1T1fEi
cfunc
    STMFD   sp!,{lr}         ; R0 already contains the object pointer
    MOV R1, #2
    BL _ZN1T1fEi
    ADD R0, R0, R0, LSL #1   ; multiply by 3
    LDMFD sp!,{pc}
    END

Alternatively, you can implement Example 4.18 and Example 4.20 using embedded assembly, as shown in Example 4.21. In this example, the __cpp keyword is used to reference the function. Therefore, you do not have to know the mangled name of the function.

Example 4.21. Implementing the function in embedded assembly

struct T {
    T(int i) : t(i) { }
    int t;
    int f(int i);
};
int T::f(int i) { return i + t; }
// Definition of asm function called from C++
__asm int asm_func(T*) {
    STMFD sp!, {lr}
    MOV R1, #2;
    BL __cpp(T::f);
    ADD R0, R0, R0, LSL #1 ; multiply by 3
    LDMFD sp!, {pc}
}
int f() {
    T t(5); // create an object of type T
    return asm_func(&t);
}

Copyright © 2002-2010 ARM. All rights reserved.ARM DUI 0203J
Non-ConfidentialID101213