Reputation: 1370
gcc has a -fvisibility option where you can define which functions are "visible" to anyone linking against your library. Although this is mainly for shared libraries, it seems it can be used for static libraries as well (see How to apply -fvisibility option to symbols in static libraries?).
Is it possible to prevent certain functions from being available to those who use my library with MSVC? I do not want my "internal" functions to all be inside a single translation unit, and therefore "static" or using an anonymous namespace will not work (AFAIK).
How can I accomplish this? Please note that I am specifically referring to static .lib libraries built using MSVC.
Thank you
Edit: I am sharing my library with other people, and therefore this is why I would like to hide certain symbols.
Upvotes: 1
Views: 1996
Reputation: 179799
No, this is not possible. A Windows "LIB" file is just a collection of OBJ files (translation units, TU's). You can use LIB.EXE /EXTRACT:member.obj Library.LIB
to see these parts. Your customers will link their TU's and your TU's together. That also includes the part where your TU's are linked to each other.
With the plan you have, it becomes impossible to link your TU's to each other. Either your TU's have their symbols visible, or they don't.
You may want to look into MSVC's Unity/Jumbo builds.
Upvotes: 2
Reputation: 5039
While I am not an expert on gcc and MSVC linker options, I guess I can give you a sensible answer:
Shared linking and static linking are very different concepts. Shared linking is done at run or load time against special prepared symbols i.e. functions. Shared linking is not standardized, and most compilers are requiring the programmer to explicitly mark functions/symbols who shall be linked to later, at run/load time. Static linking is linking at compile or link time. (compile < link < load < run time. "<" == later). Static libraries are just a way how to organize code, usually C++ things in the concepts of so called translation units in order to make the work packages smaller for the compiler, so every translation unit would be compiled to a object file. When translating an normal executable, it would just compile some objects files, and then just copy only the used stuff/symbols out of the objects files into the executable (.exe). Symbols not used will not be found in the executable usally. Static libraries are just a way to say the compiler and linker to put all symbols regardless of usage into a big file like an executable. Since they contain everything regardless if used or not they are called archives.
Shared libraries are more like an executable, by making a symbols public or non hidden, or exported, you say "This symbol will be used by the user of this shared library", so the compiler makes preparations that it can be called easily. This shared functions likely use other symbols, from object files or static libraries/archives. Symbols not transitively used by a shared symbol will be omitted i.e. not copied into the shared library (.so .dll)
As far as I understand it, the hidden function gcc offers for static libraries/symbols seems to be just, to keep gcc from marking internal/static non marked symbols, that are used by a shared symbol, as shared linkable.
However you will still find those internal symbols in the body of this shared library, if its used. However they usually can not be as simply used as the "official" exported symbols. In general code you use will be in the program which uses it. You can try to obfuscate the name of the function or symbol, usually since you wont distribute a header to this internal symbol, people will have a hard time to properly guess ABI nor API. But using a simple disassembler as reverse engineering tool its still possible.
I however recommend another tactic: C++ knows the concept of "inlining", by saying the compiler to not generate a extra object file, but just copy the body of the function into who ever uses it, you will make it very hard to identify this function, and without modification it will not be callable from extern (since it lacks the machine code for a callee)
If have taken to liberty to give you an example which also demonstrates how the gcc hidden flag doesn't work for static symbols:
#include <cstdio>
#if __GNUC__ >= 4
#define hidden __attribute__ ((visibility ("hidden")))
#else
#define hidden
#endif
hidden int hidden_func(int x, int y) {
return x * y;
}
inline int hidden_func2(int x, int y) {
return x * y;
}
int normal_func(int x, int y) {
return hidden_func(x,y) * hidden_func2(x,y);
}
int main()
{
int x{}, y{};
std:: scanf("%d %d", &x, &y);
std::printf("%d\n", normal_func(x,y));
std::printf("%d\n", hidden_func(x,y));
}
In the generated machine code, posted here https://godbolt.org/z/tFpdpE, you will see that only hidden_func2
is not visible as a symbol in the gcc and clang binary, but, since the inline
flag is only a hint for the compiler, it still can be found in the MSVC binary.
Upvotes: 1