Stripping linux shared libraries

前端 未结 6 1942
醉梦人生
醉梦人生 2020-12-12 18:00

We\'ve recently been asked to ship a Linux version of one of our libraries, previously we\'ve developed under Linux and shipped for Windows where deploying libraries is gene

相关标签:
6条回答
  • 2020-12-12 18:37

    In general, across multiple Linux and Unix systems, the answer here is that there is no answer here at link time. it's fairly fundamental to how ld.so works.

    This leads to some rather labor-intensive alternatives. For example, we rename STL to live in _STL instead of std to avoid conflicts over STL, and we use namespaces high, low, and in-between to keep our symbols away from possible conflicts with other people's symbols.

    Here's a solution you won't love:

    1. Create a small .so with only your exposed API it.
    2. Have it open the real implementation with dlopen, and link with dlsym.

    So long as you don't use RTLD_GLOBAL, you now have complete insulation if not particular secrecy .. -Bsymbolic might also be desirable.

    0 讨论(0)
  • 2020-12-12 18:46

    Actually, in the ELF structure there are 2 symbol tables: "symtab" and "dynsym" -> see this: Hiding symbol names in library

    0 讨论(0)
  • 2020-12-12 18:54

    If you wrap up your private part in an anonymous namespace then neither std::abs nor private_function can be seen in the symbol table:

    namespace{
    #include<cmath>
      float private_function(float f)
      {
        return std::abs(f);
      }
    }
    extern "C" float public_function(float f)
    {
            return private_function(f);
    }
    

    compiling (g++ 4.3.3):

    g++ -shared -o libtest.so test.cpp -s

    inspecting:

    # nm -DC libtest.so
             w _Jv_RegisterClasses
    0000200c A __bss_start
             w __cxa_finalize
             w __gmon_start__
    0000200c A _edata
    00002014 A _end
    000004a8 T _fini
    000002f4 T _init
    00000445 T public_function
    
    0 讨论(0)
  • 2020-12-12 18:55

    Just to note that Ulrich Drepper wrote an essay regarding (all?) aspects of writing shared libraries for Linux/Unix, which covers control of exported symbols amongst many other topics.

    This was very handy in making it clear how to export only functions on a whitelist from a shared lib.

    0 讨论(0)
  • 2020-12-12 18:56

    Your use of the default visibility attribute and -fvisibility=hidden should be augmented with -fvisibility-inlines-hidden.

    You should also forget about trying to hide stdlib exports, see this GCC bug for why.

    Also, if you have all of your public symbols in a specific headers you can wrap them in #pragma GCC visibility push(default) and #pragma GCC visibility pop instead of using attributes. Though if you are creating a cross platform library, take a look at Controlling Exported Symbols of Shared Libraries for a technique to unify your windows DLL and Linux DSO export strategy.

    0 讨论(0)
  • 2020-12-12 19:01

    So the solution we have for now is as follows:

    test.cpp

    #include <cmath>
    #include <vector>
    #include <typeinfo>
    
    struct private_struct
    {
        float f;
    };
    
    float private_function(float f)
    {
        return std::abs(f);
    }
    
    void other_private_function()
    {
        std::vector<private_struct> f(1);
    }
    
    extern "C" void __attribute__ ((visibility ("default"))) public_function2()
    {
        other_private_function();
    }
    
    extern "C" float __attribute__ ((visibility ("default"))) public_function1(float f)
    {
        return private_function(f);
    }
    

    exports.version

    LIBTEST 
    {
    global:
        public*;
    local:
        *;
    };
    

    compiled with

    g++ -shared test.cpp -o libtest.so -fvisibility=hidden -fvisibility-inlines-hidden -s -Wl,--version-script=exports.version
    

    gives

    00000000 A LIBTEST
             w _Jv_RegisterClasses
             U _Unwind_Resume
             U std::__throw_bad_alloc()
             U operator delete(void*)
             U operator new(unsigned int)
             w __cxa_finalize
             w __gmon_start__
             U __gxx_personality_v0
    000005db T public_function1
    00000676 T public_function2
    

    Which is fairly close to what we're looking for. There are a few gotchas though:

    • We have to ensure we don't use the "exported" prefix (in this simple example "public", but obviously something more useful in our case) in the internal code.
    • Many symbol names still end up in the string table, which appears to be down to RTTI, -fno-rtti makes them go away in my simple tests, but is a rather nuclear solution.

    I'm happy to accept any better solutions anyone comes up with!

    0 讨论(0)
提交回复
热议问题