c++shared-librariessolarissunstudiodlsym

Populate global function pointers in shared library (Solaris, Sun Studio)


I am creating a small C++ wrapper shared library around a Fortran 95 library. Since the Fortran symbols contain . in the symbol name, I have to use dlsym to load the Fortran function into a C++ function pointer.

Currently, I have a bunch of global function pointers in header files:

// test.h
extern void (*f)(int* arg);

and I populate them in the corresponding C++ file:

// test.cc
void (*f))(int* = reinterpret_cast<void(*)(int*>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_");

Questions:

  1. If I do it this way, when are these pointers populated?
  2. Can I assume them to be loaded in my executable that loads this library?
  3. In particular, can I use these functions in statically created objects in my executable or other libraries? Or does this suffer from the static initalization order fiasco?
  4. If the above way is not correct, what is the most elegant way of populating these pointers such that they can be used in static objects in executables and other libraries?

I am using the Sun Studio compiler on Solaris, if that makes a difference, but I would also be interested in a solution for GCC on Linux.


Solution

  • Where does the line

    f = reinterpret_cast<void(*)(int*)>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_"));
    

    occur in test.cc? The pointer will be initialized when the line is executed (which of course depends on when the function which contains it is called). Or did you mean to write

    void (*f)(int* ) = reinterpret_cast<void(*)(int*>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_");
    

    ? In this case, the pointer will be initialized during static initialization. Which means that you still have order of initialization issues if you try to use the pointers in the constructor of a static object.

    The classical solution for this would be to use some sort of singleton:

    struct LibraryPointers
    {
        void (*f)(int* );
        //  ...
        static LibraryPointers const& instance()
    private:
        LibraryPointers();
    };
    
    LibraryPointers const&
    LibraryPointers::instance()
    {
        static LibraryPointers theOneAndOnly;
        return theOneAndOnly;
    }
    
    LibraryPointers::LibraryPointers()
        : f( reinterpret_cast<void(*)(int*)>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_")) )
        , //  initialization of other pointers...
    {
    }
    

    Then wrap the library in a C++ class which uses this structure to get the addresses of the pointers.

    And one last remark: the reinterpret_cast you are trying to do isn't legal, at least not formally. (I think that both Sun CC and g++ will accept it, however.) According to Posix, the correct way to get a pointer to function from dlsym would be:

    void (*f)(int* );
    *reinterpret_cast<void**>(&f) = dlsym(...);
    

    This doesn't lend itself to initializations, however.