符号隐藏在使用 Xcode 构建的静态库中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3276474/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Symbol hiding in static libraries built with Xcode
提问by Ben Zotto
I'm trying to figure out whether I can build a static library that hides all of its internal objects and functions, etc, except for the interfaces I want to export. I'm experimenting with Xcode (gcc 4.2).
我试图弄清楚我是否可以构建一个静态库来隐藏其所有内部对象和函数等,除了我想要导出的接口。我正在试验 Xcode (gcc 4.2)。
I've used the __attribute__((visibility("hidden")))
attribute on some C++ classes per this documentation. I've also defined little helper C functions as being file-local (static), etc.
我已经__attribute__((visibility("hidden")))
根据本文档在某些 C++ 类上使用了该属性。我还将小助手 C 函数定义为文件本地(静态)等。
However, when I run strings
on the resulting .a library file, even when compiled in Release configuration, I still see the names of my ostensibly-hidden classes, with their method names, and even the names of file-local functions strewn around in there as well.
但是,当我strings
在生成的 .a 库文件上运行时,即使在 Release 配置中编译时,我仍然会看到我表面上隐藏的类的名称、它们的方法名称,甚至散布在那里的文件本地函数的名称以及。
I've added the -fvisibility=hidden
and even -fno-rtti
to the gcc flags. While this reduces some of the strings, the class names, method names, and static functions names are all still in there in plain or mangled-but-readable form.
我已将-fvisibility=hidden
和 甚至添加-fno-rtti
到 gcc 标志中。虽然这减少了一些字符串,但类名、方法名和静态函数名仍然以普通或错位但可读的形式存在。
Is there a reliable way to get the compiler to build this stuff without having the string names of all the internal stuff emitted into the binary? It shouldn't be necessary to have for any external clients linking in.
有没有一种可靠的方法可以让编译器构建这些东西,而无需将所有内部东西的字符串名称发送到二进制文件中?没有必要让任何外部客户端链接进来。
(To clarify: I'm asking about obfuscation of internal naming, versus literal export binding needs. I'm disconcerted that all the internal workings are visible via the strings
command, regardless of whether these symbols are formally exported or not.)
(澄清一下:我问的是内部命名的混淆,而不是字面导出绑定的需求。我感到不安的是strings
,无论这些符号是否正式导出,都可以通过命令看到所有内部工作。)
Thanks.
谢谢。
回答by bleater
Hiding internal names requires a few simple Xcode build settings, and it is not generally necessary to modify source or change the type of the built product.
隐藏内部名称需要一些简单的 Xcode 构建设置,通常不需要修改源或更改构建产品的类型。
- Eliminate any internal symbols required between modules by performing a single-object prelink. Set the Xcode build setting named "Perform Single-Object Prelink" to Yes (GENERATE_MASTER_OBJECT_FILE=YES). This causes ld to be run with the "-r" flag.
- Make sure that the setting "Strip Style" is set to "Non-global symbols" (STRIP_STYLE=non-global), this passes "-x" to ld.
- Stripping is only actually performed on static libraries if post-processing is enabled (and this is not the default). Set Xcode build setting "Deployment Postprocessing" to yes. (DEPLOYMENT_POSTPROCESSING=YES). Also make sure that "Use separate strip" is set to Yes (not always the default) (SEPARATE_STRIP=YES).
- If, in addition to local symbols, if you need to remove some of the global symbols you can supply additional options to the strip command, under the Xcode build setting "Additional strip flags". E.g. I commonly use the strip "-R somefile" option to provide a file with an additional list of symbols which I want removed from the global symbol table.
- 通过执行单对象预链接消除模块之间所需的任何内部符号。将名为“Perform Single-Object Prelink”的 Xcode 构建设置设置为 Yes (GENERATE_MASTER_OBJECT_FILE=YES)。这会导致 ld 使用“-r”标志运行。
- 确保设置“条带样式”设置为“非全局符号”(STRIP_STYLE=非全局),这会将“-x”传递给 ld。
- 如果启用后处理(这不是默认设置),则仅在静态库上实际执行剥离。将 Xcode 构建设置“部署后处理”设置为是。(DEPLOYMENT_POSTPROCESSING=YES)。还要确保“使用单独的条带”设置为是(并非总是默认值)(SEPARATE_STRIP=YES)。
- 如果除了局部符号之外,如果您需要删除某些全局符号,您可以在 Xcode 构建设置“附加条标志”下为 strip 命令提供其他选项。例如,我通常使用带“-R somefile”选项来提供一个文件,其中包含我想从全局符号表中删除的附加符号列表。
回答by Varun Gulshan
The main trick in hiding symbols within static libraries is to generate a Relocatable Object file (as opposed to a static library archive that simply consists of a collection of individual .o files). To build a relocatable object file, you need to choose your target in XCode as Bundle (as opposed to "Cocoa Touch Static Library"). The Bundle target appears under the OS X templates, and you can set its target to iOS in the Build settings if you are building for iOS.
在静态库中隐藏符号的主要技巧是生成一个可重定位的对象文件(而不是静态库存档,它只是由单个 .o 文件的集合组成)。要构建可重定位的目标文件,您需要在 XCode 中选择目标作为 Bundle(而不是“Cocoa Touch 静态库”)。Bundle 目标出现在 OS X 模板下,如果您为 iOS 构建,您可以在构建设置中将其目标设置为 iOS。
Once you have set up your target correctly, the following steps will help get the symbol hiding correct:
正确设置目标后,以下步骤将有助于正确隐藏符号:
Set the "Symbols hidden by default" option to Yes in the build settings. This makes sure all the symbols compiled in the files are marked as private.
As this is a library, you do need to keep some symbols public. You should put code for the functions you want to keep publicly visible in separate files, and compile those files with the
-fvisibility=default
flag (you can set this flag for individual files "Build Phases > Compile Sources > -- Compiler Flags" in Xcode). Alternately, you can prefix the name of the function/class that you wish to be visible with the__attribute__((visibility("default")))
directive.Under the linking settings in the X-code project, set the Mach-O type to "Relocatable Object File". What this means is that all the .o files will be relinked to generate a single object file. It is this step that helps mark all the symbols as private when the .o files are linked together into one file. If you build a static library (i.e. a
.a
file) this relinking step doesn't happen so symbols never get hidden. So choosing a Relocatable object file as your target is critical.Even after marking the symbols as private they still show up in the .o file. You need to enable stripping to get rid of the private symbols. This can be done by setting the "Stripped Linked Product" setting to Yes in the build settings. Setting this option runs the
strip -x
command on the object file that removes the private symbols from the object file.Double check all the internal symbols are gone by running the nm command on the final relocatable object file generated by the build process.
在构建设置中将“默认隐藏的符号”选项设置为是。这确保文件中编译的所有符号都标记为私有。
由于这是一个库,您确实需要公开一些符号。您应该将要公开显示的函数的代码放在单独的文件中,并使用
-fvisibility=default
标志编译这些文件(您可以在 Xcode 中为单个文件“构建阶段 > 编译源 > -- 编译器标志”设置此标志)。或者,您可以在您希望使用__attribute__((visibility("default")))
指令可见的函数/类的名称前加上前缀。在 X-code 项目中的链接设置下,将 Mach-O 类型设置为“Relocatable Object File”。这意味着所有 .o 文件将被重新链接以生成单个目标文件。当 .o 文件链接到一个文件中时,这一步有助于将所有符号标记为私有。如果您构建静态库(即
.a
文件),则不会发生此重新链接步骤,因此符号永远不会被隐藏。所以选择一个可重定位的目标文件作为你的目标是至关重要的。即使在将符号标记为私有后,它们仍会显示在 .o 文件中。您需要启用剥离以摆脱私有符号。这可以通过在构建设置中将“剥离的链接产品”设置为是来完成。设置此选项会
strip -x
在目标文件上运行命令,该命令从目标文件中删除私有符号。通过在构建过程生成的最终可重定位目标文件上运行 nm 命令,仔细检查所有内部符号是否消失。
The above steps will help you get rid of symbol names from the nm command. You'll still see some function names and file names if you run the strings command on your object file (due to some strings and object names being compiled in via exceptions). One of my colleagueshas a script that renames some of these symbols by looking into the binary sections and renaming those strings. I've posted it up here for you to use: https://gist.github.com/varungulshan/6198167. You can add this script as an extra build step in Xcode.
上述步骤将帮助您从 nm 命令中删除符号名称。如果您在对象文件上运行 strings 命令,您仍然会看到一些函数名和文件名(由于一些字符串和对象名是通过异常编译的)。我的一位同事有一个脚本,它通过查看二进制部分并重命名这些字符串来重命名其中一些符号。我已经把它贴在这里供你使用:https: //gist.github.com/varungulshan/6198167。您可以将此脚本添加为 Xcode 中的额外构建步骤。
回答by ypsu
It is a bit unclear for me how to hide the symbols in static libraries from the linux command line environment based on the previous answers so I'll just post my solution here for posterity (given this is one of the top results on google for that question).
我有点不清楚如何根据以前的答案从 linux 命令行环境中隐藏静态库中的符号,所以我将在这里发布我的解决方案以供后代使用(鉴于这是谷歌上的最佳结果之一)题)。
Let's say you have these two .c files:
假设您有这两个 .c 文件:
// f1.c
const char *get_english_greeting(void)
{
return "hello";
}
__attribute__((visibility("default")))
const char *get_greeting(void)
{
return get_english_greeting();
}
and
和
// f2.c
#include <stdio.h>
const char *get_english_greeting(void);
__attribute__((visibility("default")))
void print_greeting(void)
{
puts(get_english_greeting());
}
You want to convert these two files into a static library exporting both get_greeting
and print_greeting
but not get_english_greeting
which you don't want to make static as you would like to use it throughout your library.
您想将这两个文件转换为一个静态库,同时导出两个文件get_greeting
,print_greeting
但get_english_greeting
您不想将其设为静态,因为您希望在整个库中使用它。
Here are the steps to achieve that:
以下是实现这一目标的步骤:
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
Now this works:
现在这有效:
// gcc -L. main.c -lf
void get_greeting(void);
void print_greeting(void);
int main(void)
{
get_greeting();
print_greeting();
return 0;
}
And this doesn't:
而这不会:
// gcc -L. main.c -lf
const char *get_english_greeting(void);
int main(void)
{
get_english_greeting();
return 0;
}
For the latter you get this error:
对于后者,您会收到此错误:
/tmp/ccmfg54F.o: In function `main':
main.c:(.text+0x8): undefined reference to `get_english_greeting'
collect2: error: ld returned 1 exit status
Which is what we want.
这就是我们想要的。
Note that the hidden symbol names are still visible in the static library but the linker will refuse to link with them outside said static library. To completely remove the symbol names you'll need to strip and obfuscate.
请注意,隐藏符号名称在静态库中仍然可见,但链接器将拒绝在所述静态库之外与它们链接。要完全删除符号名称,您需要剥离和混淆。