Weak symbols and dlopen() with clang vs. gcc - gcc

I've got a library that defines something like this:
//singleton.hpp
class Singleton
{
public:
static Singleton* getInstance()
{
static Singleton* mInstance=0;
if (!mInstance)
{
mInstance=new Singleton();
}
return mInstance;
}
};
I include this header when building a couple of shared object libraries. When I build these shared object libraries with gcc (Ubuntu), the static gets marked as unique:
(nm output)
0000000000045780 u Singleton::mInstance
When I build the shared libraries with clang the same symbol gets marked as weak:
0000000000045780 V Singleton::mInstance
When I dlopen(..., RT_NOW) the gcc-built shared objects, the dynamic linker fixes everything up and seems to make a single mInstance symbol. However, when I dlopen(..., RT_NOW) the clang-built shared objects, I get a separate symbol for each library, which makes the singleton not a singleton. Is this expected behavior? Is there some way I can force the dynamic linker to behave as if the symbols were marked as unique, as they are with the gcc compilation?

Looks like https://llvm.org/bugs/show_bug.cgi?id=22281
However it is not marked as resolved and doesn't provide workarounds.

Related

Mixing dynamic and static linking with gcc

ALL,
I know static linking is frown upon in *nix world, but...
I made a static library that exports a class and will be used by other (dynamic) libraries.
So, as an example I have foo.a, bar.so and baz.so.
bar.so use the class from foo.a and functions from baz.so. baz.so is not written by me and so does not use anything from those 2 libraries. foo.a exported class is not using anything from bar or Baz libraries.
Generally speaking, foo.a is an interface which contains a class with a bunch of pure virtual functions that are implemented inside bar.so
So, now my question is - how do I properly link them?
TIA!!
EDIT:
I tried basic -L/path/to/library -lfoo -L/path/to/library -lbar, but am getting ld error during the run-time that class from foo is not there.

Why do not symbol conflict when contain same static library?

There is static library name libstatic1.a, another static library named libstatic2.a test app named testapp
libstatic1.a has a method testcmethds
libstatic2.a linked libstatic1.a, and called testcmethds in method samecalltest
testapp linked libstatic1.a and libstatic2.a
testapp will complie successfully and normal running.
Why there didn't have symbol conflict, i use nm -a to check two .a lib, it have same method symbol.
//in libstatic1.a
//...
0000000000000000 T _testcmethds
//...
//in libstatic2.a
//...
0000000000000000 T _testcmethds
//...
Why there didn't have symbol conflict
There isn't a conflict because the linker never pulls in the object containing _testcmethds from libstatic2.a into the link.
To understand this better, read this or this.
Note: the design in which the same global symbol(s) appear in multiple libraries is exceedingly fragile. A day will come when you'll regret designing things that way.

How to pass unique_ptr object as argument to a class that is a library

I read all the questions and answers related to passing unique_ptr as argument to a class constructor and those answers worked for classes within the exe. But here im trying to pass an unique_ptr object to a class constructor that is pre-compiled as static library.
This class in the library looks something like this,
// Class declaration (in a header file)
class TScreen
{
private:
std::unique_ptr<TProcess> m_process;
public:
__fastcall TScreen(int a, std::unique_ptr<TProcess> i_process);
};
// The constructor definition (in a separate .cpp file)
__fastcall TScreen::TScreen(int a, std::unique_ptr<TProcess> i_process):
m_process(std::move(i_process))
{
}
I will be trying to instantiate the class TScreen in the exe like this,
void TScreen_Main::CallScreen()
{
std::unique_ptr<TProcess> objprocess (new TProcess());
std::unique_ptr<TScreen> objscreen (new TScreen(0, std::move(objprocess)));
}
I compiled the library and imported it to the exe. When i compile the exe, it gives me a link error like this,
[ilink32 Error] Error: Unresolved external '__fastcall TScreen::TScreen(int, std::unique_ptr<TProcess, std::default_delete<TProcess> >)' referenced from TSCREEN_MAIN.OBJ
[ilink32 Error] Error: Unable to perform link
I tried the same with boost::shared_ptr as well and it gives me the same error. But it works fine with raw pointers, but not with smart pointers and i cannot figure out why?
Thanks in advance.
Your problem here is a linking issue. Now, exactly what's going on is difficult for me to say because I never work in a Windows environment, and linking is something that (while very similar) has some distinct differences between a Unix/Linux and a Windows environment.
My guess is that if you explicitly declare your constructor to be inline, and declare that the definition is inline, it will work correctly.
This presumes that the fact that you put the declaration of the class and definition together indicates that the definition is in the header file with the class.
When the compiler sees that it's declared inline it will emit a definition into every compilation unit where it's needed. The linker should then eliminate all the duplicate definitions.
If you really are defining the constructor in some .cpp file separate from the .hpp file that the class is in, and you compiler that .cpp file into .obj file that eventually makes it into a .lib or .dll that you link against when creating the executable, then I don't know what the problem is. If this is the case, you should use the tools that should come with your development environment to see what symbols are actually in the library or the dll because somehow the symbol for the constructor definition isn't there.

gcc symbol resolution shadowing

I'm trying to add some custom code to our internal libc related to atexit handling.
In our libc we define this because we link to custom CRT files and don't use GCC's which defines this.
void *__dso_handle __attribute__((__visibility__("hidden"),__weak__)) = &__dso_handle;
GCC also adds this to binaries when linking them.
In the libc is the function atexit which just calls
int atexit(void (*func)(void))
{
return __cxa_atexit((void (*)(void*))func, NULL, __dso_handle);
}
The issue I'm facing is that the _dso_handle value used is the local one from libc when I'd like to make it dynamically fetch the one from the module that calls atexit() at runtime so that the proper dso is registered with the atexit function.
I checked attributes and I found nothing that could help there.
Note that unlike glibc, atexit is kept in the dynamic version of libc to preserve backwards compatibility with older binaries.
The issue I'm facing is that the _dso_handle value used is the local one from libc when I'd like to make it dynamically fetch the one from the module that calls atexit() at runtime
Your module can call __cxa_atexit instead, and pass in whatever dso_handle you desire.

SmartPointer from DLL: where to construct & destruct

I'm currently remodelling a dynamic library project and removed a lot of STL and other dependencies from its header resulting in conflicting implementations between different toolchains.
The DLL Interface now only contains plain C-types and custom types whom implementation depends solely on the DLL code. But now I'm stuck with two remaining points.
The DLL should return some sort of reference counting smart pointer (with a weak pointer option)
Managing construction and destruction between the DLL boundaries. This more or less looks like this.
.
#include <memory>
class Config;
typedef std::shared_ptr<Config> ConfigPtr;
class CONFIGAPI_DLL Config
{
public:
///...
ConfigPtr getNewNode( char const* query = "." )
{
// construct obj in dll, but construct shared_ptr in header
return ConfigPtr( _constructgetNewNode(query) );
}
ConfigPtr getNewNodeFromHeader( char const* query = "." )
{
// construct obj and shared_ptr in header
auto obj = new Config;
obj->_init(query);
return ConfigPtr( obj );
}
private:
Config* _constructNewNode( char const* query = "." );
void _init( char const* query = "." );
};
I was thinking by creating the share_ptr at the dll headers (getNewNode) it would prevent mixed implementations of std::shared_ptr ...but I don't know if that is a good idea?
But I also construct the new object inside the DLL (_constructNewNode) and this means it should also be destructed there?
I tried to construct it in the headers and so in the user code scope (getNewNodeFromHeader)... this shouldn't cause problems?
The downside is I still export the C++11 header and rule out all older compilers. Is it possible to export the shared_ptr type from the dll as unconflicting code but still be compatible with std::shared_ptr?
thanks!
I suppose you want to mix creation and destruction of the objects (Config and the shared_ptr). If the DLL client is not compiled with the same version and configuration of the compiler you would be in troubles (for example, mixing debug and release modules). The main problem I see here: there is not any type of standard ABI for C++.
I was thinking by creating the share_ptr at the dll headers
(getNewNode) it would prevent mixed implementations of std::shared_ptr
...but I don't know if that is a good idea?
If you define your header file to create the shared_ptr, that would be OK if only a module use that header file. I mean, if the shared_ptr is not to be used for the content of the DLL, for example. BUT if other client module (a binary module, like other DLL) use also that header, you must be sure they are compiled with the same compiler and compiling configuration. If you have not that guarantee, then is not good idea.
But I also construct the new object inside the DLL (_constructNewNode)
and this means it should also be destructed there?
If you construct the object inside the DLL, you'll be better destroying inside the DLL. How to do that? specifying a deleter at shared_ptr construction. Something like
struct ConfigDeleter {
void operator()(Config* c) {
c->destroy(); // or as you want to implement it.
};
typedef std::shared_ptr<Config, ConfigDeleter> ConfigPtr;
I tried to construct it in the headers and so in the user code scope
(getNewNodeFromHeader)... this shouldn't cause problems?
As before, it depends if you can guarantee all modules are homogeneous (same compiler version and configuration, library, etc.). But of you want to implement as that, do it well:
// construct obj and shared_ptr in header
auto obj_ = make_shared<Config>();
obj_->init(query);
It is exception-safe and more efficient: just one allocation to store the object and the reference, instead two allocations in your sample.
If you want your code be safe for mixing modules, implement all allocations (shared_ptr included) into the DLL, if they are shared. Exports a "C" interface, and create header file to wrap that interface in classes. Something like:
class WConfig {
public:
WConfig(): m(IDll->create()) {
}
// other member functions as interface stub
~WConfig() {
IDll->release(m);
}
private:
Config* m;
};
To share this object, you can use copy constructor (that copy the pointer and call to IDll->reference(m), for example) or any other approach.

Resources