Limiting visibility of symbols when linking shared libraries

不问归期 提交于 2019-11-26 03:28:16

问题


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?


回答1:


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



回答2:


I think the easiest way of doing that is adding the -fvisibility=hidden to gcc options and explicitly make visibility of some symbols public in the code (by __attribute__((visibility("default")))). See the documentation here.

There may be a way to accomplish that by ld linker scripts, but I don't know much about it.




回答3:


The code generated to call any exported functions or use any exported globals is less efficient than those that aren't exported. There is an extra level of indirection involved. This applies to any function that might be exported at compile time. gcc will still produce extra indirection for a function that is later un-exported by a linker script. So using the visibility attribute will produce better code than the linker script.




回答4:


If you are using libtool, there is another option much like Employed Russian's answer.

Using his example, it would be something like:

cat export.sym
bar
baz

Then run libtool with the following option:

libtool -export-symbols export.sym ...

Note that when using -export-symbols all symbols are NOT exported by default, and only those in export.sym are exported (so the "local: *" line in libfoo.version is actually implicit in this approach).




回答5:


Seems there's several ways to manage exported symbols on GNU/Linux. From my reading these are the 3 methods:

  • Source code annotation/decoration:
    • Method 1: -fvisibility=hidden along with __attribute__((visibility("default")))
    • Method 2 (since GCC 4): #pragma GCC visibility
  • Method 3: Version script (aka "symbol maps") passed to the linker (eg. -Wl,--version-script=<version script file>)

I won't get into examples here since they're mostly covered by other answers, but here's some notes, pros & cons to the different approaches off the top of my head:

  • Using the annotated approach allows the compiler to optimize the code a bit (one less indirection).
  • If using the annotated approach, then consider also using strip --strip-all --discard-all.
  • The annotated approach can add more work for internal function-level unit tests since the unit tests may not have access to the symbols. This might require building separate files: one for internal development & testing, and another for production. (This approach is generally non-optimal from a unit test purist perspective.)
  • Using a version script loses the optimization but allows symbol versioning which seems to not be available with the annotated approach.
  • Using a version script allows for unit testing assuming code is first built into an archive (.a) file and then linked into a DSO (.so). The unit tests would link with the .a.

I'm sure there are others.

Here's some references (with examples) that I've found helpful:

  • http://blog.fesnel.com/blog/2009/08/19/hiding-whats-exposed-in-a-shared-library/
  • https://accu.org/index.php/journals/1372
  • https://akkadia.org/drepper/dsohowto.pdf


来源:https://stackoverflow.com/questions/435352/limiting-visibility-of-symbols-when-linking-shared-libraries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!