Node:ASM and C, Next:, Previous:ASM GPF, Up:Converting

17.4 Problems with combining assembly and C/C++ modules

Q: Which register can I safely change in my assembly code that is called from a C program?

Q: How come my program that calls assembly-language functions crashes with a GPF, but only if I compile it with -O2?

Q: When I try to link my assembly modules with a C++ program, the linker complains about the functions I wrote in assembly!

A: You can safely clobber EAX, ECX, EDX, FS and GS, as well as EFLAGS and the floating-point registers (including the FPU control and status words), but must save and restore all other registers at the end of your assembly function. Failure to preserve, e.g., ESI, EDI, EBX, ESP or DS in functions written in assembly can cause a C program linked with such functions to crash, since GCC expects those registers to be preserved across function calls. Special-purpose registers such as GDTR, LDTR, CR*, and DR*, although GCC and the DJGPP library don't use them, should probably not be touched at all, but if you do, it's a good idea to save and restore them.

Functions written in assembly or in C that are meant to be linked with C++ programs should be declared extern "C" in their prototype, like this:

#ifdef __cplusplus
extern "C" {
#endif

int my_assembly_func (int);

#ifdef __cplusplus
}
#endif

This example shows how to produce a prototype that would work with both C and C++ programs; it is usually placed in a .h header file that is meant to be #included in the C or C++ programs.

This extern "C" declaration prevents the C++ compiler from mangling the names of external functions according to the usual C++ rules. (The name-mangling is needed because C++ allows several different functions to have the same name but different types of arguments.)