1

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

是否可以阻止将我的库与 MSVC 一起使用的人使用某些功能?我不希望我的“内部”函数都在一个翻译单元内,因此“静态”或使用匿名命名空间将不起作用(AFAIK)。

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

谢谢

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

4

2 回答 2

2

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

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

您可能想查看 MSVC 的Unity/Jumbo构建。

于 2020-06-12T12:44:43.507 回答
0

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

共享链接和静态链接是非常不同的概念。共享链接是在运行或加载时针对特殊准备好的符号(即函数)完成的。共享链接不是标准化的,大多数编译器都要求程序员在运行/加载时显式标记稍后链接的函数/符号。静态链接是在编译或链接时链接。(编译 < 链接 < 加载 < 运行时间。“<” == 稍后)。静态库只是一种组织代码的方式,通常是所谓的翻译单元概念中的 C++ 东西,以使编译器的工作包更小,因此每个翻译单元都会被编译成一个目标文件。当翻译一个普通的可执行文件时,它只会编译一些对象文件,然后只将使用过的东西/符号从对象文件中复制到可执行文件(.exe)中。通常不会在可执行文件中找到未使用的符号。静态库只是说明编译器和链接器将所有符号(无论使用情况如何)放入像可执行文件这样的大文件中的一种方式。因为无论是否使用它们都包含所有内容,因此它们被称为档案。

共享库更像是一个可执行文件,通过将符号设为公开或非隐藏或导出,您说“此符号将被此共享库的用户使用”,因此编译器做好了可以轻松调用的准备。此共享函数可能使用来自目标文件或静态库/档案的其他符号。共享符号未传递使用的符号将被省略,即不会复制到共享库 (.so .dll)

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

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

然而我推荐另一种策略:C++ 知道“内联”的概念,通过说编译器不生成额外的目标文件,而只是将函数的主体复制给曾经使用它的人,你将很难识别它函数,并且未经修改将无法从外部调用(因为它缺少被调用者的机器代码)

如果冒昧地给您一个示例,该示例还演示了 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("%d\n", normal_func(x,y));
    std::printf("%d\n", hidden_func(x,y));
}

在生成的机器代码中,张贴在这里https://godbolt.org/z/tFpdpE,您会看到 onlyhidden_func2在 gcc 和 clang 二进制文件中不作为符号可见,但是,因为该inline标志只是编译器的提示,它仍然可以在 MSVC 二进制文件中找到。

于 2020-06-12T12:11:42.530 回答