限制静态库中符号的可见性 (MSVC/Visual C++)

Limit visibility of symbols in static library (MSVC/Visual C++)

本文关键字:MSVC Visual C++ 可见性 静态 符号      更新时间:2023-10-16

gcc 有一个 -fvisibility 选项,您可以在其中定义哪些函数对链接到您的库的任何人"可见"。虽然这主要用于共享库,但它似乎也可以用于静态库(请参阅如何将 -fvisibility 选项应用于静态库中的符号?

是否可以阻止某些功能可供使用我的库和 MSVC 的用户使用?我不希望我的"内部"函数都位于单个翻译单元中,因此"静态"或使用匿名命名空间将不起作用(AFAIK(。

我怎样才能做到这一点?请注意,我特别指的是使用 MSVC 构建的静态 .lib 库。

谢谢

编辑:我正在与其他人共享我的图书馆,因此这就是为什么我想隐藏某些符号。

不,这是不可能的。Windows"LIB"文件只是OBJ文件(翻译单元,TU(的集合。您可以使用LIB.EXE /EXTRACT:member.obj Library.LIB来查看这些部分。您的客户会将他们的 TU 和您的 TU 链接在一起。这还包括您的 TU相互链接的部分。

有了你的计划,就不可能将你的TU相互链接起来。您的 TU 要么其符号可见,要么不可见。

你可能想看看MSVC的Unity/Jumbo版本。

虽然我不是 gcc 和 MSVC 链接器选项的专家,但我想我可以给你一个明智的答案:

共享链接和静态链接是非常不同的概念。共享链接是在运行或加载时针对特殊准备的符号(即函数(完成的。共享链接不是标准化的,大多数编译器都要求程序员在运行/加载时显式标记稍后应链接到的函数/符号。 静态链接是在编译或链接时链接。(编译<链接><加载>

<运行时。"> 共享库更像是一个可执行文件,通过将一个符号设为公开或非隐藏,或导出,你说"这个符号将被这个共享库的用户使用",所以编译器做了准备,可以很容易地调用它。此共享函数可能使用对象文件或静态库/存档中的其他符号。共享符号未传递使用的符号将被省略,即不会复制到共享库中(.so .dll(

据我了解,gcc 为静态库/符号提供的隐藏功能似乎是公正的,以防止 gcc 将共享符号使用的内部/静态非标记符号标记为共享可链接。

但是,您仍然可以在此共享库的正文中找到这些内部符号(如果使用(。然而,它们通常不能像"官方"出口符号那样简单地使用。通常,您使用的代码将在使用它的程序中。您可以尝试混淆函数或符号的名称,通常由于您不会将标头分发到此内部符号,因此人们将很难正确猜测 ABI 或 API。但是使用简单的反汇编器作为逆向工程工具仍然是可能的。

然而,我推荐另一种策略:C++知道"内联"的概念,通过说编译器不生成额外的对象文件,而只是将函数的主体复制到使用它的人中,您将很难识别此函数,并且如果不进行修改,它将无法从 extern 调用(因为它缺少被调用者的机器代码(

如果冒昧地给你一个例子,它也演示了 gcc 隐藏标志如何不适用于静态符号:

#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("%dn", normal_func(x,y));
std::printf("%dn", hidden_func(x,y));
}

在生成的机器代码中,https://godbolt.org/z/tFpdpE 发布在这里,您将看到只有hidden_func2在 gcc 和 clang 二进制文件中不可见为符号,但是,由于inline标志只是编译器的提示,它仍然可以在 MSVC 二进制文件中找到。