| |||
| Home > Mixing C, C++, and Assembly Language > Calling between C, C++, and ARM assembly language > Examples of calling between languages | |||
The following sections contain code examples that demonstrate how to mix language calls:
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:
Type armasm --debug scopy.s to
build the assembly language source.
Type armcc -c --debug strtest.c to
build the C source.
Type armlink strtest.o scopy.o -o strtest to
link the object files.
Run the image using a compatible debugger with an appropriate debug target.
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
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;
}
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
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;
}
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
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);
}
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);
}