8.4.3. Examples

The following code examples demonstrate how to:

The examples assume a no software stack checking and no frame pointer APCS variant.

Example 8.9 shows a C program that uses a call to an assembly language subroutine to copy one string over the top of another string.

Example 8.9.  Calling assembly language from C

#include <stdio.h>
extern void strcopy(char *d, char *s);
int main()
{	char *srcstr = "First string - source ";
	char *dststr = "Second string - destination ";
	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);
}

The ARM assembly language module that implements the string copy subroutine:

		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 zero terminator.
		BNE		strcopy			; Keep going if not.
		MOV		pc,lr			; Return.
		END

Example 8.9 is located in the examples\asm subdirectory of your installation directory as strtest.c and scopy.s. Follow these steps to build the example:

  1. Type armasm scopy.s at the command line to build the assembly language source.

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

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

  4. Type armsd strtest to load the files into the command-line debugger, and type go at the debugger command line to execute the example.

Example 8.10 shows how to call C from assembly language.

Example 8.10.  Calling C from assembly language

Define the function in C to be called from the assembly language routine:

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

In assembly language:

	; int f(int i) { return -g(i, 2*i, 3*i, 4*i, 5*i); }
	EXPORT f
	AREA f, CODE, READONLY
	IMPORT g
	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
	RSB r0, r0, #0						; negate result
	LDR pc, [sp], #4						; return
	END

Example 8.11.  Calling a C function from C++

Declare and call the C function in 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;
}

Define 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 8.12.  Calling assembly language from C++

Declare and call the assembly language function in 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;
}

Define the function in ARM assembly language:

	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]
	MOV pc, lr
	END

Example 8.13.  Calling C++ from C

Define 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++
	p->i += 5;								// function to be called from
}									// C. The function is
									// written in C++, only the
									// linkage is C		

Declare and call the function in C:

struct S {
	int i;
};
extern void cppfunc(struct S *p);									/* Declaration of the C++ */
									/* C++ function to be */
									/* 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 8.14.  Calling a C++ function from assembly language

Define the function to be called in C++:

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

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

	AREA Asm, CODE
	IMPORT cppfunc 						; import the name of the C++ 
							; function to be called from Asm
	EXPORT		f
f
	STMDB		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
	LDMIA		sp!,{pc}
	END

Example 8.15.  Calling a C++ member function from C or assembly language

The following code demonstrates how to call a non-static, non-virtual C++ member function from C or assembly language.

In C++:

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);
}

In C:

struct T;
extern int f__1TFi(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 * f__1TFi(t, 2);							/* like '3 * t->f(2)' */
}

Or, implementing cfunc() in ARM assembly language:

	EXPORT		cfunc
	AREA		cfunc, CODE
	IMPORT		f__1TFi
	STMDB		sp!,{lr}						; r0 already contains the 
									; object pointer
	MOV		r1, #2
	BL		f__1TFi
	ADD		r0, r0, r0, LSL #1						; multiply by 3
	LDMIA		sp!,{pc}
	END

Example 8.16.  Passing a reference between C and C++ functions

In C++:

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++
										// to be called from C.
	return 7 * r;
}
int f() {
	int i = 3;
	return cfunc(i);								// passes a pointer to 'i'
}

In C:

extern int cppfunc(const int*);									/* declaration of the C++ */
									/* 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);
}
Copyright © 1997, 1998 ARM Limited. All rights reserved.ARM DUI 0040D
Non-Confidential