隐藏在用Xcode / gcc构build的静态库中的符号

我试图找出是否可以build立一个静态库,隐藏所有的内部对象和函数等,除了我想要导出的接口。 我正在试验Xcode(gcc 4.2)。

我已经在本文档的某些C ++类上使用了__attribute__((visibility("hidden")))属性。 我也已经定义了小助手C函数作为文件本地(静态)等

但是,当我在生成的.a库文件上运行strings时,即使在Releaseconfiguration中编译时,仍然可以看到我的表面隐藏类的名称,方法名称,甚至文件本地函数的名称那里也是。

我已经添加了-fvisibility=hidden ,甚至-fno-rtti到gcc标志。 虽然这减less了一些string,但是类名称,方法名称和静态函数名称仍然以简单或不可读的forms存在。

有没有一种可靠的方法让编译器构build这些东西,而不必将所有内部的东西发送到二进制文件的string名称? 不需要连接任何外部客户端。

(为了澄清:我在询问关于内部命名的混淆,而不是字面的输出绑定需求,我很不满意所有的内部工作都可以通过strings命令看到,不pipe这些符号是否正式导出。

谢谢。

隐藏内部名称需要一些简单的Xcode构build设置,通常不需要修改源代码或更改构build产品的types。

  1. 通过执行单对象预链接消除模块之间所需的任何内部符号。 将名为“执行单对象预链接”的Xcode构build设置设置为是(GENERATE_MASTER_OBJECT_FILE = YES)。 这导致ld以“-r”标志运行。
  2. 确保“Strip Style”设置为“非全局符号”(STRIP_STYLE =非全局),这会将“-x”传递给ld。
  3. 如果启用后处理(这不是默认设置),则仅在静态库上执行清除操作。 设置Xcode的构build设置“部署后处理”为yes。 (DEPLOYMENT_POSTPROCESSING = YES)。 还要确保“使用单独的条”设置为“是”(并非总是默认值)(SEPARATE_STRIP = YES)。
  4. 如果除了本地符号,如果需要删除一些全局符号,则可以在Xcode构build设置“Additional strip flags”下为strip命令提供附加选项。 例如,我通常使用带“-R somefile”选项来提供一个文件,其中包含我想要从全局符号表中删除的附加符号列表。

在静态库中隐藏符号的主要技巧是生成一个可重定位的对象文件(而不是静态库存档,它只包含一个单独的.o文件集合)。 要构build一个可重定位的目标文件,你需要在XCode中select你的目标为Bundle(而不是“Cocoa Touch Static Library”)。 Bundle目标出现在OS X模板下,如果您正在为iOS构build,您可以在Build设置中将其目标设置为iOS。

一旦你正确的设置你的目标,下面的步骤将帮助正确的符号隐藏:

  1. 在构build设置中将“默认情况下隐藏的符号”选项设置为“是”。 这确保文件中编译的所有符号都被标记为私有。

  2. 由于这是一个图书馆,你需要公开一些符号。 你应该把代码保存在不同的文件中公开显示,并用-fvisibility=default标志编译这些文件(你可以设置这个标志为单独的文件“Build Phases> Compile Sources> – Compiler Flags” Xcode中)。 或者,您可以使用__attribute__((visibility("default")))指令将希望显示的函数/类的名称加上前缀。

  3. 在X-code项目的链接设置下,将Mach-Otypes设置为“Relocatable Object File”。 这意味着所有.o文件将被重新链接以生成单个对象文件。 当.o文件链接到一个文件中时,这一步有助于将所有符号标记为私有。 如果你build立一个静态库(即一个.a文件)这个重新链接步骤不会发生,所以符号永远不会被隐藏。 所以select一个Relocatable对象文件作为你的目标是非常重要的。

  4. 即使将这些符号标记为私有,它们仍然显示在.o文件中。 您需要启用剥离来摆脱私有符号。 这可以通过在构build设置中将“已剥离链接产品”设置设置为“是”来完成。 设置此选项会在目标文件上运行strip -x命令,从目标文件中删除专用符号。

  5. 通过在构build过程生成的最终可重定位目标文件上运行nm命令,仔细检查所有内部符号。

以上步骤将帮助您摆脱nm命令中的符号名称。 如果您在对象文件上运行strings命令(由于某些string和对象名称是通过例外编译的),您仍然会看到一些函数名称和文件名。 我的一个同事有一个脚本,通过查看二进制部分并重命名这些string来重命名这些符号。 我已经把它贴在这里给你使用: https : //gist.github.com/varungulshan/6198167 。 您可以在Xcode中添加此脚本作为额外的构build步骤。

我有点不清楚如何根据以前的答案在linux命令行环境中隐藏静态库中的符号,所以我只是在这里发布我的解决scheme后人(鉴于这是谷歌顶级的结果之一题)。

假设你有这两个.c文件:

 // f1.c const char *get_english_greeting(void) { return "hello"; } __attribute__((visibility("default"))) const char *get_greeting(void) { return get_english_greeting(); } 

 // f2.c #include <stdio.h> const char *get_english_greeting(void); __attribute__((visibility("default"))) void print_greeting(void) { puts(get_english_greeting()); } 

您希望将这两个文件转换为导出get_greetingprint_greeting的静态库,但不会将get_english_greeting为静态,因为您希望在整个库中使用它。

以下是实现该步骤的步骤:

 gcc -fvisibility=hidden -c f1.c f2.c ld -r f1.o f2.o -o libf.o objcopy --localize-hidden libf.o ar rcs libf.a libf.o 

现在这个工作:

 // gcc -L. main.c -lf void get_greeting(void); void print_greeting(void); int main(void) { get_greeting(); print_greeting(); return 0; } 

这不是:

 // gcc -L. main.c -lf const char *get_english_greeting(void); int main(void) { get_english_greeting(); return 0; } 

对于后者,你会得到这个错误:

 /tmp/ccmfg54F.o: In function `main': main.c:(.text+0x8): undefined reference to `get_english_greeting' collect2: error: ld returned 1 exit status 

这是我们想要的。

请注意,隐藏的符号名称在静态库中仍然可见,但链接器将拒绝在静态库之外链接它们。 要完全删除符号名称,您需要去除和混淆。