Interoperability Between C Language and ARM Assembly Language
1. Accessing C Language Global Variables from Assembly
Global variables can only be accessed indirectly through their addresses. To access global variables in C, you must first introduce the global variable using the extern directive, and then load its address into a register.
For unsigned char type, use LDRB/STRB;
For unsigned short type, use LDRH/STRH;
For unsigned int type, use LDR/STR;
For char type, use LDRSB/STRSB;
For short type, use LDRSH/STRSH;
Example:
.text
.global asmsubroutine
.extern globvar
asmsubroutine:
LDR R1,=globvar
LDR R0,[R1]
ADD R0,R0,#2
STR R0,[R1]
MOV PC,LR
.end
2. C Program Calling Assembly Program
A C program calls an assembly program by first declaring the assembly module to be called with extern, ensuring that the number of parameters matches the number of variables required in the assembly module, and that parameter passing adheres to the ATPCS rules before calling it in the C program.
Example:
#include<stdio.h>
extern void *strcopy(char*d,char*s);// Module declaration
int main()
{
char*srcstr=”first”;
char*dststr=”second”;
strcopy(dststr,srcstr);// Calling assembly module;
}
.text
.global strcopy
Strcopy:
LDRB R2,[R1],#1
STRB R2,[R0],#1
CMP R2,#0
BNE Sstcopy
MOV PC,LR
.end
Assembly Program Calling C Program
Before calling, the number of parameters required by the C module must be completed according to the ATPCS parameter rules, with the first four parameters passed through R0-R3, and subsequent parameters passed via the stack, then the B or BL instruction is used to call.
Example:
int g(int a,int b,int c,int d,int e)// C function prototype
{
return(a+b+c+d+e);
}
The assembly language computes the result of i+2i+3i+4i+5i;
.global _start
.text
_start:
.extern g; // Import C program
STR LR,{SP,-#4}!; // Save PC
ADD R1,R0,R0
ADD R2,R1,R0
ADD R3,R1,R2
STR R3,{SP,#-4}!
ADD R3,R1,R1
BL g; // Call C function g
ADD SP,SP,#4
LDR PC,[SP],#4
.end
return(0);
Interoperability Between C and C++ Libraries
A friend asked me last night about calling C++ libraries from C. After lunch today, due to a severe neck pain, I couldn’t join our group’s “Daily Battle” so I took the opportunity to summarize the interoperability between C and C++ libraries.
1. Understanding extern “C”:
Many people think that “C” represents the C language, but it actually refers to a linkage convention, applied more between C and C++ due to their close relationship. In fact, Fortran and assembly language often use it as they also comply with C’s implementation conventions.
The extern “C” directive describes a linkage convention. It does not affect the definition of the called function; even with this declaration, function type checks and parameter conversions must still adhere to C++ standards, not C.
2. The Role of extern “C”:
The linking characteristics of different languages vary, which also determines the differences in their compiled linkage symbols. For example, a function void fun(double d) compiled by C will produce a symbol like _fun, and the C linker assumes the parameter type information is correct as long as it finds the symbol. On the other hand, C++ compiles this function into a symbol like _fun_double or _xxx_funDxxx, adding type information to the symbol, which is also why C++ can implement overloading.
Thus, linking a library compiled with a C compiler directly with C++ will inevitably lead to unrecognized symbol issues. This is where extern “C” comes in; it tells the compiler to compile and link the encapsulated functions in a C language manner.
3. Example of Calling C Library in C++:
1). Create a C Dynamic Library:
Compile and copy to the system library directory (you can also define your own library directory, man ldconfig):
[root@coredump test]# gcc –shared -o libhello.so hello.c
[root@coredump test]# cp libhello.so /lib/
2). Write a C++ program to call it:
Compile and run:
[root@coredump test]# g++ test.cpp -o test -lhello
[root@coredump test]# ./test
hello
[root@coredump test]#
3). Conditional Compilation with __cplusplus Macro:
Why add this conditional compilation? As Xiao Shenyang puts it: “Little sister, why is that?”
This technique may also be used in C++ files generated from C header files to establish common C and C++ files, ensuring that when this file is compiled as a C file, the C++ structures can be removed. In other words, the extern “C” syntax is not allowed in a C compilation environment.
For example: rename the above test.cpp to test.c, change the header file to stdio.h, remove the conditional compilation, and compile with gcc to see the effect. However, even with those changes, if compiled with g++, it will work normally, which illustrates the meaning of “common C and C++ files”.
4. C Calling C++ Library:
Calling a C++ library from C doesn’t seem to be too difficult, as C++ has forward (to C) compatibility, combined with the inherent extern “C” convention, making everything feel natural. However, getting C to call a C++ library seems more challenging, but it’s not impossible.
At this point, I need to take a break; it’s noon, and I need to step out for a smoke. But I believe if you don’t know the answer, you’ll be looking for bricks to throw at me, eager to crack my skull open. I understand; I’m used to it. I have a senior who, upon seeing me, would throw a brick first!
Back to the point, we still need to rely on the pure extern “C”.
1) Create a C++ Library:
Compile and copy to the system library directory:
[root@coredump test]# g++ –shared -o libworld.so world.cpp
[root@coredump test]# cp libworld.so /lib/
2) Create a middle interface library to encapsulate the C++ library:
The method m_world is a secondary encapsulation of the world method in the libworld library. Compile and copy to the system library directory:
[root@coredump test]# g++ –shared -o libmid.so mid.cpp -lworld
[root@coredump test]# cp libmid.so /lib/
3). The C program calls the C++ library through the linked intermediate interface library:
Compile and run:
[root@coredump test]# gcc test.c -l mid -o test
[root@coredump test]# ./test
world
[root@coredump test]#
Note: If the C++ library contains classes, temporary objects can be created in the secondary interface functions to call the corresponding functional functions, of course, depending on the actual situation.