Avoid name mangling on a shared object C interface under linux - c++

Under windows we have a C interface (extern "C" { // interface }) to our C++ library, that exports unmangled functions using a module definition file (.def).
I am trying to recreate the same thing under linux, where I am relatively inexperienced. I understand that under NIX systems, all functions are exported by default. With this in mind I created a shared object, which I ran through the nm command.
I was surprised to see that, unlike in windows, my function names had been mangled!
How can I prevent this please?

The usual solution is to declare the functions extern "C". This not only causes the names to be mangled as in C, but also for the function to use the C calling conventions.

Related

Function is declared, but not defined in shared library

I have a source code of some library. There is a function that is only declared (in a header file), but not defined in the source code.
extern "C" {
extern int theFunc(int);
}
What is the reason to have only a declaration of a function in a library?
In addition of Mike Kinghan's answer (which covers most of the cases), there is also a (rather unusual) reason to declare in the library header file a function not implemented in that library. Sometimes, that library expects a plugin and the user is expected to provide such a plugin (in some way, perhaps passing the plugin file name to some other function). The library would use dynamic loading techniques (such as dlopen(3) on Linux) to install such a plugin. And it would fetch some particular function (with dlsym(3) on Linux) from the plugin. Then it makes sense to declare, but not define such a plugin function, in the library headers.
I do admit that this case is unusual and contrived.
For a concrete example, read about GCC plugins. Your plugin should #include "gcc-plugin.h" which indirectly declares
/* Declaration for "plugin_init" function so that it doesn't need to be
duplicated in every plugin. */
extern int plugin_init (struct plugin_name_args *plugin_info,
struct plugin_gcc_version *version);
but that plugin_init should be defined by your plugin code. Then GCC would dlopen your plugin, using something equivalent to
void*plhdl = dlopen("/home/you/yourplugin.so", RTLD_NOW);
and later get a function pointer using
typeof(plugin_init)* funptr = dlsym(plhdl, "plugin_init");
Notice that the symbol plugin_init does not appear in the code segment of GCC.
Another example is the Qt framework (a set of libraries). Read about Qt plugins.

Why is extern "C" used with shared object library determined at runtime?

I saw in a C++ program that dlfcn library is used for dynamically
linking to a shared object library chosen by the user of the C++
program during runtime, and for calling functions in the chosen
shared object library via dlsym() and other functions in dlfcn.
Assume the user chooses a shared object library called x.so during runtime. x.so was compiled from a cpp file with definitions
of functions enclosed within extern "C". A comment in the cpp file
says that the usage of extern "C" is important but without further
explanation, and I wonder why?
Is it correct that there is only C++ code and no C code involved here? So is extern "C" not necessarily only used when mixing C and C++
code together?
Does whether dlfcn library is statically or dynamically linked to the C++ program matters to the questions above?
Now compare to a simpler case, where the shared object library is
known much earlier than runtime, and the author of the C++ program
specifies it in the C++ program without using dlfcn before compiling it, and then
dynamically links the shared object library and the C++ program
during runtime. In this case, is `extern "C" still necessary in the
cpp file which was compiled into the shared object library?
Thanks.
extern "C" changes the linkage, and affects name mangling. See What is name mangling, and how does it work?
Without it, exported names in the compiled object will normally be mangled. That means that they cannot be used from C. It also means that looking them up via dlsym() requires using the mangled name.
Is it correct that there is only C++ code and no C code involved here? So is extern "C" not necessarily used when mixing C and C++ code together?
It is not clear what you mean here. If you are compiling C++, then only C++ code is involved at this stage. If you are then linking in any way with a module written in C, then C is involved. If you need an external C library or program to link to your C++-defined functions, then they need to be declared extern "C".
Does whether dlfcn library is statically or dynamically linked to the C++ program matters to the questions above?
No (perhaps you should have explained why you think it might matter).
Now compare to a simpler case, where the shared object library is known much earlier than runtime, and the author of the C++ program specifies it in the C++ program without using dlfcn before compiling it, and then dynamically links the shared object library and the C++ program during runtime. In this case, is `extern "C" still necessary in the cpp file which was compiled into the shared object library?
It is necessary that the declared linkage of the symbols is consistent in the two C++ modules. Certainly, you could remove extern "C" if the modules are both C++. But if one module declares the symbol as extern "C" then the other must also.

Is extern "C" required also for linking global variables used in Cpp file to the one defined in a cfile?

Is extern "C" required also for linking global variables used in Cpp file to the one defined in a c file?
It is used for linking function from C++ file which is referenced in C file because of the name mangling of function names in C++ files. Does the C compiler also changes the name of variables??
Is extern "C" required also for linking global variables used in Cpp file to the one defined in a c file?
Portably, yes.
You might find that leaving out extern "C" works for your compiler (for example, GCC, which doesn't mangle C++ variable names in the global namespace), but that's not something you can rely on for all compilers.
Does the C compiler also changes the name of variables??
It depends on the compiler (specifically, on the ABI it uses). The language standards don't specify how language-level names map to linker symbols, so different compilers can use different name-mangling schemes.
It is not required for variables. Extern "C" is required for functions because in C++ the functions can be defined multiple times for different number and type of parameters. Each function name includes parameters in encoded form. But the variables cannot be redefined and the names are identical (compatible) in C and C++.

C/C++ mangle exports in a specific way

Due to specific needs i need to create a DLL which exports a function that is named in a specific way, it's also mangled.
?drawGdi#stop#234##Z
Is there anyway of accomplishing this?
You can do that, but you have to write a DEF file.
foo.h:
extern "C" declspec(dllexport) void foo(int);
foo.def:
EXPORTS
?drawGdi#stop#234##Z=_foo
(_foo is the exported name of the function).
Remember to specify the DEF file when linking the DLL, of course.
For more details see the documentation on DEF files.
Can't you declare your function like e.g.
class myclass;
extern "C" void my_function(int,myclass&);
Then it should be exported as my_function (at least on Posix systems; I guess it is the same on Windows, but I don't know).
If compiling with GCC, you could use Asm Labels. Then any name acceptable by the assembler should be ok.
On Linux with ELF executables you probably could not, as David Schwartz suggested, simply edit the binary file (because that would probably break some hash-table used in ELF for symbols).

How do I resolve link errors that appear in Objective-C++ but not Objective-C?

I'm converting my App Delegate file from .m to .mm (Objective-C to Objective-C++) so that I can access a third-party library written in Objective-C++. In Objective-C, my app delegate builds and runs fine. But when I change the extension, the project builds and I get link errors, all of which are missing symbols from a static library written in C that I use. The errors are classic link errors with the following format:
"MyFunction(arguments)", referenced from:
-[MyAppDelegate myMethod] in MyAppDelegate.o
Symbol(s) not found
All of the problems are in the app delegate object. I know that I'm all set to compile Objective-C++ because my ViewController file is .mm. So my question has a few parts to it.
First, are these symbols truly not there in the sense that I can't use them? In other words, is it not possible to access plain old C functions from an Objective-C++ file? If this is true, that's pretty unfortunate. I thought that almost all Objective-C code, and certainly all Objective-C code that at least builds as .mm, was valid Objective-C++. Am I wrong?
If not, any idea how I can prevent these errors? Are there header rules that are different in Objective-C++ that I don't know about?
Thanks for any and all help.
Link errors with mixed C++/C or C++/Objective-C programs are usually due to C++ name mangling. Make sure you have extern "C" attached to all the appropriate declarations, and also that all of your code agrees on the linkage. That is, make sure that the function definition as well as the places where it is used can all see the extern "C" or extern "C++".
In your particular situation, it looks like MyFunction() is getting compiled with C++ linkage and having its name mangled, but that your myMethod Objective-C file is trying to link against the unmangled name.
Here is a link to the wikipedia article about name mangling.
Surround your header include with extern C.
This tells the linker that the function names in the library do not get C++ name mangling.
E.g.:
extern "C" {
#include "my-lib.h"
}