Limitando a visibilidade de símbolos ao vincular bibliotecas compartilhadas

Algumas plataformas exigem que você forneça uma lista de símbolos externos de uma biblioteca compartilhada ao vinculador. No entanto, na maioria dos sistemas unixish isso não é necessário: todos os símbolos não-estáticos estarão disponíveis por padrão.

Meu entendimento é que o conjunto de ferramentas GNU pode, opcionalmente, restringir a visibilidade apenas aos símbolos explicitamente declarados. Como isso pode ser alcançado usando o GNU ld?

    O GNU ld pode fazer isso em plataformas ELF.

    Veja como fazer isso com um script de versão do vinculador:

     /* 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 ' 

    Por padrão, todos os símbolos são exportados:

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

    Digamos que você queira exportar apenas bar() e baz() . Crie um “script de versão” libfoo.version :

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

    Passe para o linker:

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

    Observe os símbolos exportados:

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

    Acho que a maneira mais fácil de fazer isso é adicionar a opção -fvisibility=hidden às opções do gcc e tornar explicitamente a visibilidade de alguns símbolos públicos no código (por __attribute__((visibility("default"))) )). Veja a documentação aqui .

    Pode haver uma maneira de realizar isso por meio de scripts de link ld, mas não sei muito sobre isso.

    O código gerado para chamar qualquer function exportada ou usar qualquer exportação global é menos eficiente do que aqueles que não são exportados. Existe um nível extra de indireção envolvida. Isso se aplica a qualquer function que possa ser exportada em tempo de compilation . O gcc ainda produzirá uma indireção extra para uma function que é posteriormente não exportada por um script de vinculador. Portanto, usar o atributo visibility produzirá um código melhor que o script vinculador.

    Se você estiver usando o libtool, existe outra opção muito parecida com a resposta do Employed Russian.

    Usando o exemplo dele, seria algo como:

     cat export.sym bar baz 

    Em seguida, execute o libtool com a seguinte opção:

     libtool -export-symbols export.sym ... 

    Observe que ao usar -export-symbols, todos os símbolos NÃO são exportados por padrão, e somente aqueles em export.sym são exportados (portanto, a linha “local: *” no libfoo.version é, na verdade, implícita nessa abordagem).