3

I have a program that statically links with several c++ libraries that export a few functions:

extern "C" 
{ 
    KSrvRequestHandler* CreateRequestHandler( const char* name );
    bool                DestroyRequestHandler( KSrvRequestHandler* handler );
    const char**        ListRequestHandlerTypes();
}

The main program then calls these functions using GetProcAddress/dlsym:

#ifdef WIN32

   HINSTANCE hDll = GetModuleHandle( NULL );

   mCreateHandler   = GetProcAddress( hDll, createFuncName  );
   mDestroyHandler  = GetProcAddress( hDll, destroyFuncName );
   mGetHandlerTypes = GetProcAddress( hDll, listFuncName    );

#else // POSIX

   void* handle = dlopen( NULL, 0 );

   mCreateHandler   = dlsym( handle, createFuncName  ); 
   mDestroyHandler  = dlsym( handle, destroyFuncName ); 
   mGetHandlerTypes = dlsym( handle, listFuncName    ); 
   dlclose( handle );

#endif // !POSIX

So the key here is that I'm calling a function in my own main program using dynamic linking.

( Why I do this is beyond the scope of the question, but short answer: this is a plugin architecture, but I have some standard plugins that are linked directly into the main binary - but I still want to load them through the same plugin loading interface. E.g. for the built-in plugins I load them by passing in the current executable as the source of the plugin interfaces. )

Here is the problem: the linker doesn't know I'm going to need these functions and doesn't link them in.

How do I force these functions to be linked in? For a dynamic lib, exporting them is enough. But for an exe, even dll exported function are deleted by the linker.

I know I can probably force linking by making the main binary assign these function addresses to something or some other similar hack. Is there a right way to do this?

@UPDATE: So I have a solution that works - but it sure is ugly on the inside. Still looking for a better way.

So I have to somehow define the symbols I need in the object that loads the built-in interfaces. I don't think there is a way to force the linker to link in a symbol otherwise. E.g. There is no way that I know of to build a library with a function that is always linked wether it looks needed or not. This is entirely at the discretion of the link step for the executable.

So in the executable I have a macro that defines the built-in interfaces I need. Each built-in plugin has a prefix to all of its interface functions so, at the top of the file I do:

DEFINE_BUILT_IN_PLUGIN( PluginOne )
DEFINE_BUILT_IN_PLUGIN( PluginTwo )

This will force the definitions of the functions I need. But the macro to do this is so ugly that I'm filled with feelings of rage and self doubt ( I've removed the trailing slashes from the macro for readability ):

#define FORCE_UNDEFINED_SYMBOL(x) 
    void* _fp_ ## x ## _fp =(void*)&x; 
    if (((ptrv) _fp_ ## x ##_fp * ( rand() | 1 )) < 1 ) 
        exit(0);

#define DEFINE_BUILT_IN_PLUGIN( PREFIX )  

extern "C" 
{                                                                                                   
    KSrvRequestHandler* PREFIX ## CreateRequestHandler( const char* name );
    bool                PREFIX ## DestroyRequestHandler( KSrvRequestHandler* handler );      
    const char**        PREFIX ## ListRequestHandlerTypes();
}  

class PREFIX ## HandlerInterfaceMagic
{      
public:
    PREFIX ## HandlerInterfaceMagic()
    {
        FORCE_UNDEFINED_SYMBOL( PREFIX ## CreateRequestHandler );
        FORCE_UNDEFINED_SYMBOL( PREFIX ## DestroyRequestHandler );
        FORCE_UNDEFINED_SYMBOL( PREFIX ## ListRequestHandlerTypes ); 
    }
};               
PREFIX ## HandlerInterfaceMagic PREFIX ## HandlerInterfaceMagicInstance;

Since the compiler is an optimizing genuis, in FORCE_UNDEFINED_SYMBOLS I'm going to great lengths to trick the compiler into linking an unreferenced function. That macro only works inside a function. So I have to create this bogus Magic class. There must be a better way.

Anyway - it does work.

Rafael Baptista
  • 11,181
  • 5
  • 39
  • 59
  • I may be misunderstanding your situation, but can you move the exported functions to a separately-compiled library, and then link them in from the library as they're needed? – Adam Liss Jun 12 '13 at 23:04
  • That would work if I put the built-in plugins into their own dynamic library - essentially just writing them as regular plugins that always ship with the executable. But this is suboptimal in that I would prefer them to all be in the same file. But bigger problem is that the built-in plugins need to have access into the internals of the main program. E.g. one of them is a diagnostic plugin that reports in internal program state. I'd have to create a whole reverse interface ( e.g. exe->plugin) to do this with the diag plugin as a separate dyn. lib. – Rafael Baptista Jun 13 '13 at 14:07
  • Please don't use leading double underscores for symbol names, those are reserved for the compiler. If you're worried about name collisions, put them in a namespace. – Mark Ransom Jun 13 '13 at 15:48

3 Answers3

3

I have seen at least two different approaches to solve similar tasks.

  1. In Qt for example, you can have static plug-ins which need to be "imported" into the main executable by calling a specific macro:

    https://qt-project.org/doc/qt-4.8/qtplugin.html#Q_IMPORT_PLUGIN

    It creates a static instance of a custom class whose constructor calls an initialization function exported from the static plug-in.

  2. The Poco guys force the export of a specific symbol from the static library using an extern "C" declaration on Linux and a pragma on Windows:

    __pragma(comment (linker, "/export:CreateRequestHandler"))

    The linkage to the static library is forced with the same extern "C" declaration on Linux and with a linker pragma on Windows:

    __pragma(comment (linker, "/include:CreateRequestHandler"))

    You can find the details in this blog post.

Sascha
  • 1,104
  • 8
  • 15
  • Thanks for this. It is reassuring that Qt solved this in a similar way to what I've done in my own very ugly import macro. – Rafael Baptista Jun 13 '13 at 14:12
  • Yes, but if I understood your case correctly, your extern "C" function is just a dummy. In Qt, the function actually needs to be called (during static initialization of the importing executable or shared library) and registers the static plug-in. – Sascha Jun 13 '13 at 14:26
  • It seems that in the QT example, QT exports to the plugins a registration api, and at static init time it calls into them to get the plugin to install itself. In my case the system loads plugins as configured in a config file. So the system is in control of wether or not plugins load. So all it needs is for the plugin functions to be available either in plugin dynamic libs, or compiled into the main system. I'm forcing their inclusion now by a bogus use of the function pointer addresses to force linking. If the optimizer gets any smarter it will stop linking them in again. – Rafael Baptista Jun 13 '13 at 15:05
0

Can't you provide a .def file to your main executable linker? That file should export the functions in question, which would keep them from being deleted.

I seem to remember that I did something like this long ago.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
0

Problem: On windows, STATIC LIB which contains an OBJ file that has a function marked __decl-spec(dll¬export) but if the same is not used in the EXE, function does not get exported from the EXE. On other platforms also we have the same problem BUT there we have compiler options like --whole-archive / -force_load, do make it work.

Links: Link1 Link2

Only solution that come to my mind is to not create STATIC libs, rather include all code (static LIBS) in the executable then: 1. It works on Windows 2. It works on Linux without --whole-archive 3. It works on Mac OS X without -force_load 4. We also need not worry about if 2 & 3 include the dead code, exe bloat etc.

This is the only solution till the linkers become smart and throw out every unused symbol, except those marked specifically for external consumption i.e. marked to be exported.

Abhishek Jain
  • 9,614
  • 5
  • 26
  • 40