符号隐藏在使用 Xcode 构建的静态库中

发布于 2024-09-10 08:52:27 字数 743 浏览 10 评论 0原文

我想弄清楚是否可以构建一个静态库来隐藏其所有内部对象和函数等,除了我想要导出的接口之外。我正在尝试 Xcode (gcc 4.2)。

我在一些 C++ 类上使用了 __attribute__((visibility("hidden"))) 属性,每个 本文档。我还将一些辅助 C 函数定义为文件本地(静态)等。

但是,当我在生成的 .a 库文件上运行 strings 时,即使在发布配置中编译,我仍然查看我表面上隐藏的类的名称及其方法名称,甚至还散布在其中的文件本地函数的名称。

我已将 -fvisibility=hidden 甚至 -fno-rtti 添加到 gcc 标志中。虽然这减少了一些字符串,但类名称、方法名称和静态函数名称仍然以普通或损坏但可读的形式存在。

有没有一种可靠的方法可以让编译器构建这些东西,而无需将所有内部东西的字符串名称发送到二进制文件中?任何外部客户端都不需要链接。

(澄清一下:我问的是内部命名的混淆,而不是文字导出绑定的需要。我感到不安的是,所有内部工作都可以通过 strings 命令,无论这些符号是否正式导出。)

谢谢。

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).

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.

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.

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.

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.)

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

若有似无的小暗淡 2024-09-17 08:52:27

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

  1. 通过执行单对象预链接消除模块之间所需的任何内部符号。将名为“执行单对象预链接”的 Xcode 构建设置设置为“是”(GENERATE_MASTER_OBJECT_FILE=YES)。这会导致 ld 使用 -r 标志运行。
  2. 确保“Strip Style”设置为“非全局符号”(STRIP_STYLE=non-global),这会将 -x 传递给 ld。
  3. 如果启用后处理(这不是默认设置),则仅在静态库上实际执行剥离。将 Xcode 构建设置“部署后处理”设置为 yes。 (DEPLOYMENT_POSTPROCESSING=YES)。另请确保“使用单独条带”设置为“是”(并不总是默认值)(SEPARATE_STRIP=YES)。
  4. 如果除了本地符号之外,如果您需要删除一些全局符号,您可以提供 -unexported_symbols_list file 命令(其中 file 是文本文件的路径要删除的符号数,每行一个)或使用 Xcode 将 -unexported_symbol symbol 命令(其中 symbol 是要删除的单个符号名称)添加到单对象预链接步骤构建设置“单对象预链接标志”(即 PRELINK_FLAGS)。不要忘记使用修饰符号名称;例如,C 函数的符号将以 _ 字符为前缀的函数名称。
    (或者,也可以在 Xcode 构建设置“附加条带标志”下使用 strip 命令的附加选项来完成此操作,例如 -R file 选项,该选项与 ld 的 unexported_symbols_list 具有相同的效果选项)。

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.

  1. 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.
  2. Make sure that the setting "Strip Style" is set to "Non-global symbols" (STRIP_STYLE=non-global), this passes -x to ld.
  3. 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).
  4. If, in addition to local symbols, if you need to remove some of the global symbols you can supply the -unexported_symbols_list file command (where file is the path to a text file of symbols to remove, one per line) or the -unexported_symbol symbol command (where symbol is a single symbol name to remove) to the single-object prelink step using the Xcode build setting "Single-Object Prelink Flags" (i.e. PRELINK_FLAGS). Don't forget to use the decorated symbol name; for example the symbol for a C function will be the function name prefixed with the _ character.
    (Alternately, this can also be done using additional options to the strip command, under the Xcode build setting "Additional strip flags", e.g. -R file option which has the same effect as ld's unexported_symbols_list option).
人海汹涌 2024-09-17 08:52:27

在静态库中隐藏符号的主要技巧是生成可重定位对象文件(而不是仅由单个 .o 文件的集合组成的静态库存档)。要构建可重定位目标文件,您需要在 XCode 中选择目标作为 Bundle(而不是“Cocoa Touch Static Library”)。 Bundle 目标出现在 OS X 模板下,如果您正在构建 iOS,则可以在构建设置中将其目标设置为 iOS。

正确设置目标后,以下步骤将有助于正确隐藏符号:

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

  2. 由于这是一个库,您确实需要公开一些符号。您应该将要公开可见的函数的代码放在单独的文件中,并使用 -fvisibility=default 标志编译这些文件(您可以为各个文件设置此标志“Build Phases > Compile” Xcode 中的来源 > -- 编译器标志)。或者,您可以使用 __attribute__((visibility("default"))) 指令为您希望可见的函数/类的名称添加前缀。

  3. 在 X-code 项目的链接设置下,将 Mach-O 类型设置为“可重定位对象文件”。这意味着所有 .o 文件将被重新链接以生成单个目标文件。当 .o 文件链接到一个文件中时,此步骤有助于将所有符号标记为私有。如果您构建静态库(即 .a 文件),则不会发生此重新链接步骤,因此符号永远不会隐藏。因此,选择可重定位目标文件作为目标至关重要。

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

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

    通过

上述步骤将帮助您从 nm 命令中删除符号名称。如果您在目标文件上运行 strings 命令,您仍然会看到一些函数名称和文件名(由于某些字符串和对象名称是通过异常编译的)。我的一位同事有一个脚本,可以通过查看二进制部分并重命名这些字符串来重命名其中一些符号。我已将其发布在这里供您使用: https://gist.github.com/varungulshan/6198167 。您可以将此脚本添加为 Xcode 中的额外构建步骤。

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.

Once you have set up your target correctly, the following steps will help get the symbol hiding correct:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. Double check all the internal symbols are gone by running the nm command on the final relocatable object file generated by the build process.

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 colleagues has 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.

故乡的云 2024-09-17 08:52:27

我有点不清楚如何根据之前的答案从 Linux 命令行环境中隐藏静态库中的符号,因此我将在这里发布我的解决方案以供后代使用(鉴于这是 google 上的最佳结果之一)问题)。

假设您有这两个 .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

这就是我们想要的。

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

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).

Let's say you have these two .c files:

// 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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文