Search code examples
linuxgccg++shared-librariesfunction-interposition

how to link with two shared libraries with many conflicting functions


I'm currently linking with two third party shared libraries (A.so and B.so) on linux. the problem is that both of the two so's linked statically with another library, as a result there are about 400 functions from A.so and B.so having the same names. When I compile and link with -lA -lB, or -lB -lA, depending on the order the functions are picked up from A or B separately as a result of function interposition which caused problem and the code cannot run. I'm wondering if there's a way to bind function names to their libraries so both libraries can be linked and used? because those overlapping function names are called internally within A and B, so I can't use things like objcopy, etc. will dlopen help?


Solution

  • I'm wondering if there's a way to bind function names to their libraries so both libraries can be linked and used?

    When the two libraries were linked, they should have controlled the symbols they export, and should have hidden the "other" library, but they didn't ...

    will dlopen help?

    Yes: if you dlopen("A.so", RTLD_LOCAL); and dlopen("B.so", RTLD_LOCAL);, then neither library will be added to the global scope, and they will not "see" each other.

    You'll have to explicitly lookup symbols you need from A.so and B.so, but that's the best you could do.

    Update:

    is there a quick way to link to a static library without exporting symbols from that "other" library while building A.so

    This is best done by using -fvisibility=hidden flag and __attribute__((visibility("default"))) on symbols that should be exported. Example:

    #define EXPORTED __attribute__((visibility("default")))
    
    struct Foo {
      void EXPORTED ExportedFunction();
      void EXPORTED AnotherExportedFunction();
      void InternalFunction();
    };
    
    void Foo::ExportedFunction() { }
    void Foo::AnotherExportedFunction() { }
    void Foo::InternalFunction() { }
    
    
    gcc -shared -fPIC -o foo.so foo.cc
    nm -CD foo.so  | grep Foo::
    00000000000005fc T Foo::ExportedFunction()
    0000000000000610 T Foo::InternalFunction()
    0000000000000606 T Foo::AnotherExportedFunction()
    

    Without explicit export control, everything gets exported (including InternalFunction we don't want).

    gcc -shared -fPIC -o foo.so foo.cc -fvisibility=hidden
    nm -CD foo.so  | grep Foo::
    00000000000005bc T Foo::ExportedFunction()
    00000000000005c6 T Foo::AnotherExportedFunction()
    

    Voilà: only things we explicitly wanted to export are.