Inline function visibility under -fvisibility=hidden in GCC
0 reputation · 06 Oct 2023, 16:22 UTC
0 reputation · 06 Oct 2023, 16:22 UTC
When building a shared library with -fvisibility=hidden, the goal is to keep all non‑static symbols hidden unless explicitly marked default. However, the treatment of inline functions defined in header files is not settled across GCC releases; some versions emit such functions with default visibility when they are not eliminated, while others respect the hidden default.
This inconsistency can cause accidental API exposure and complicates reproducible builds, especially when the same header is used in multiple translation units. Clarifying the conditions under which GCC decides to give default versus hidden visibility to these inline functions would help library maintainers enforce intended symbol boundaries.
Does GCC 13 emit header‑defined inline functions with hidden visibility when -fvisibility=hidden is set and the function remains out‑of‑line? Does adding -fvisibility-inlines-hidden produce a consistent hidden result across GCC 10, 12, and 13? Is there a portable attribute or pragma that forces hidden visibility for such inline functions irrespective of compiler version?
33275 reputation · 06 Oct 2023, 22:54 UTC
In GCC 13, when -fvisibility=hidden is specified, any header-defined inline function that is emitted as a standalone symbol (out-of-line) will have hidden visibility by default. GCC 13 does not introduce a specific exception that elevates inline functions to default visibility if they lack an explicit attribute.
The -fvisibility-inlines-hidden flag does not provide a consistent result across GCC 10, 12, and 13 because its behavior depends on the language being compiled:
-fvisibility=hidden already implies this behavior for C++ inlines.-fvisibility=hidden and the linkage rules of the chosen C standard (e.g., C11 vs GNU89).Adding this flag will not resolve visibility leaks in pure C libraries across these versions.
Because compiler flags can be overridden or behave differently across languages, the most portable way to force hidden visibility for internal inline functions is to use a guarded attribute macro. This ensures the symbol remains hidden regardless of the global visibility setting.
#if defined(__GNUC__) || defined(__clang__)
#define INTERNAL_HIDDEN __attribute__((visibility("hidden")))
#else
#define INTERNAL_HIDDEN
#endif
// Usage in header
INTERNAL_HIDDEN inline void internal_helper(void) {
// implementation
}
To confirm that your inline functions are not leaking into the public API, do not rely on nm alone, as it may show symbols in the standard symbol table (.symtab) that are not exported. Instead, check the dynamic symbol table:
readelf --dyn-syms libyourlibrary.so | grep internal_helper
If the function is correctly hidden, it will either be absent from this output or marked as LOCAL. If it appears as GLOBAL with DEFAULT visibility, it is being exported.
Missing Diagnostic Detail: To provide a more precise recommendation, please specify if you are compiling as C or C++ and which -std flag (e.g., -std=c11 or -std=gnu89) is in use, as C inline linkage varies significantly between these standards.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.