-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] Use version-script instead of symbol visibility to control export-list of shared libraries #6722
Comments
Thanks for the write up! While I acknowledge all the problems listed here, I wonder if that's a symptom of Taichi itself not having a good control over header-inclusion rules. That is, even if some third party libs don't care about symbol visibility at all, if we are careful enough such that these third party libs are never used in public headers, we should still be fine?
+1. This is the most standard way to control visibility, to my knowledge. (We probably discussed this before) Note that I'm not suggesting we should not consider version-script. I wonder if we can get to a point where public headers are super clean, should we be able to go back to symbol visibility? I also wonder if C++20' module should magically make these problems all disappear.. |
IMO, the nature of visibility makes it hard to exhaust all the unnecessary symbols. The killing problem is that visibility is a Following is an example to demonstrate how symbols from third-party library can get leaked to the shared library: Suppose C-API only release one interface named Both C-API and taichi_core.a are compiled with Note that C-API neither directly link, nor uses any symbol from Example codec_api.h
c_api.cpp
taichi_core/core.h
taichi_core/core.cpp
third_party/third_party.h
third_party/third_party.cpp
Resultsreadelf -s c_api.cpp.o
readelf -s taichi_core/core.cpp.o
readelf -s third_party/third_party.cpp.o
readelf -s libtaichi_c_api.soJust because we linked with |
So visibility itself is not able to exhaust unexpected symbols, and we have to either use |
Thank you so much for the explanation! |
Issue: fix #5872, RFC #6722 *Note: This PR will also remove GGUI symbols from libtaichi_c_api.so on MacOS. Do not have this PR merged until we replaced all the GGUI renderers in taichi-aot-demos. **After this PR, libtaichi_c_api.so exports the following symbols:** Linux: [c_api_linux_exports.txt](https://github.com/taichi-dev/taichi/files/10102729/c_api_linux_exports.txt) Windows: [c_api_windows_exports.txt](https://github.com/taichi-dev/taichi/files/9624666/c_api_windows_exports.txt) MacOS: [c_api_mac_exports.txt](https://github.com/taichi-dev/taichi/files/9624830/c_api_mac_exports.txt)
Issue: fix taichi-dev#5872, RFC taichi-dev#6722 *Note: This PR will also remove GGUI symbols from libtaichi_c_api.so on MacOS. Do not have this PR merged until we replaced all the GGUI renderers in taichi-aot-demos. **After this PR, libtaichi_c_api.so exports the following symbols:** Linux: [c_api_linux_exports.txt](https://github.com/taichi-dev/taichi/files/10102729/c_api_linux_exports.txt) Windows: [c_api_windows_exports.txt](https://github.com/taichi-dev/taichi/files/9624666/c_api_windows_exports.txt) MacOS: [c_api_mac_exports.txt](https://github.com/taichi-dev/taichi/files/9624830/c_api_mac_exports.txt)
Subtask of #6793
A common problem with shared libraries are symbol collision due to unexpected symbol exports.
For example
libtaichi_c_api.so
accidentally exports the global variablellvm::AllSubCommands
from statically linkedlibLLVM.a
library, which conflicts with symbol of the same name but exported fromlibLLVM.so
:To avoid symbol collisions, we want all the symbols to have "LOCAL" bind type and only export those appeared in the C-API header files. There are two distinct techniques to achieve that, namely
symbol visibility
andversion script
.Symbol Visibility
Brief introduction to symbol visibilty
Symbol visibility specifies how symbol should be resolved by dynamic linker when linking with a shared library (https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Code-Gen-Options.html#Code-Gen-Options). To resolve symbol collision, we should at least set
visibility=protected
which prohibits symbol preemption. To prevent symbols being directly used in the user code, we should then setvisibility=hidden
.Drawbacks of symbol visibility
Setting symbol visibility uses a compile-time option instead of link-time option. The compiler tags symbols in each compile unit (.cpp) and then automatically determines their visibility when linking to the shared library.
readelf -s c_api.cpp.o:
readelf -s libc_api.so:
( You'll notice that compiler will automatically turn a GLOBAL symbol with
visibility=hidden
to a LOCAL symbol due to the same behavior. )Guarding the export-list of a shared library through symbol visibility relies on strict control over each individual symbol, which is why people suggest setting all symbols to
hidden
by default and explicitly mark symbols to export asdefault
(https://gcc.gnu.org/wiki/Visibility). However, this practice still have the following problems:libtaichi_c_api.so
,libtaichi_python.so
,libtaichi_export_core.so
), then they have to compromise to the least strict visibility (default
)Version script
On the contrary,
version-script
(https://nxmnpg.lemoda.net/1/ld.lld) is a link-time option and serves as a gatekeeper to guarantee only symbols satisfied certain rules will be exported from a shared library, which is a more exhaustive way to exclude any unexpected symbols from being exported.The text was updated successfully, but these errors were encountered: