Search code examples
linkershared-librariesgnulinker-scripts

Limiting visibility of symbols when linking shared libraries


Some platforms mandate that you provide a list of a shared library's external symbols to the linker. However, on most unixish systems that's not necessary: all non-static symbols will be available by default.

My understanding is that the GNU toolchain can optionally restrict visibility just to symbols explicitly declared. How can that be achieved using GNU ld?


Solution

  • GNU ld can do that on ELF platforms.

    Here is how to do it with a linker version script:

    /* foo.c */
    int foo() { return 42; }
    int bar() { return foo() + 1; }
    int baz() { return bar() - 1; }
    
    gcc -fPIC -shared -o libfoo.so foo.c && nm -D libfoo.so | grep ' T '
    

    By default, all symbols are exported:

    0000000000000718 T _fini
    00000000000005b8 T _init
    00000000000006b7 T bar
    00000000000006c9 T baz
    00000000000006ac T foo
    

    Let's say you want to export only bar() and baz(). Create a "version script" libfoo.version:

    FOO {
      global: bar; baz; # explicitly list symbols to be exported
      local: *;         # hide everything else
    };
    

    Pass it to the linker:

    gcc -fPIC -shared -o libfoo.so foo.c -Wl,--version-script=libfoo.version
    

    Observe exported symbols:

    nm -D libfoo.so | grep ' T '
    00000000000005f7 T bar
    0000000000000609 T baz