Keep the exported function from being deleted by the linker

I have a program in which statically links with several C ++ libraries that export several 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 call the function in my own main program using dynamic linking.

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

Here's the problem: the linker does not know that I will need these functions and will not bind them.

How to make these functions communicate? For dynamic lib, just export them. But for exe, even the exported dll function is removed by the linker.

I know that I can possibly force a link by forcing the main binary code to assign these function addresses to something or another similar hack. Is there a proper way to do this?

@UPDATE: So, I have a solution that works, but it is necessarily ugly inside. Still looking for a better way.

Therefore, I need to somehow define the characters that I need in the object that loads the built-in interfaces. I don't think there is a way to force the linker to refer to a character otherwise. For instance. I do not know how to build a library with a function that is always related to the fact that it looks necessary or not. This is entirely at the discretion of the link stage for the executable.

So, in the executable, I have a macro that defines the built-in interfaces that I need. Each built-in plugin has a prefix for 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 me to define the functions that I need. But the macro for this is so ugly that I am filled with feelings of anger and self-doubt (I removed 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 draw great conclusions to trick the compiler into binding the unreferenced function. This macro only works inside a function. So I have to create this dummy magic class. There must be a better way.

In any case, it works.

+2
source share
3 answers

I have seen at least two different approaches to solving such problems.

  • In Qt, for example, you can have static plugins that you need to “import” into the main executable file 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 the initialization function exported from the static plug-in.

  • Poco guys force them to export a specific character from a static library using the extern "C" declaration on Linux and the pragma on Windows:

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

    Linking to a static library is mandatory with the same extern "C" declaration on Linux and using the pragma linker on Windows:

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

    Details can be found in this post.

+2
source

Can you provide a .def file for the main executable linker? This file should export the functions in question, which will not allow them to be deleted.

I think I remember that I did something a long time ago.

0
source

Problem: in windows there is a STATIC LIB that contains an OBJ file that has a function marked __decl-spec (dll¬export), but if it is not used in EXE, the function is not exported from EXE. Other platforms also have the same problem, but we have compiler options such as --whole-archive / -force_load, to get the job done.

Links: Link1 Link2

The only solution that comes to my mind is not to create STATIC libraries, but to include all the code (static LIBS) in the executable file, and then: 1. It works on Windows 2. It works on Linux without -all- archive 3. It runs on Mac OS X without -force_load 4. We also do not need to worry about if 2 and 3 include dead code, exe bloat, etc.

This is the only solution, until the linkers become smart and throw out every unused symbol, except for those that are specifically designed for external consumption, that is, marked for export.

0
source

Source: https://habr.com/ru/post/958582/


All Articles