在静态iOS库中重写符号

5
我正在开发一个iOS应用程序,它链接了几个静态库。挑战在于,这些链接的库定义了相同名称但实现不同的方法。奇怪的是,我没有收到任何“重复符号定义”错误;但是,毫不意外地,我最终只能访问该方法的一个实现。
更明确地说,假设我有libA和libB,它们都定义了一个名为func1()的全局C方法。
当我同时链接libA和libB,并调用func1()时,它会解析为libA或libB的实现,而没有编译警告。然而,我需要能够分别访问libA的func1()和libB的func1()。 有一个类似的SO帖子解释了如何在C中完成此操作(通过符号重命名),但不幸的是,正如我所发现的那样,objcopy工具无法用于ARM架构(因此也无法用于iPhone)。
(我将提交它到App Store,因此动态链接不是一个选项)

如果您拥有这两个库的源代码,那么解决方案就很明显了。或者,您可以使用 lipo 将这两个库打包成一个库,这样应该(如果我的记忆没有出错的话)只会保留一个符号。 - Richard J. Ross III
谢谢@RichardJ.RossIII,但是我没有源代码,也不确定你的建议是否有帮助,因为我想要将这些符号分开保留,我需要它们都,不想将它们合并成一个符号。 - Ege Akpinar
我建议使用dlopendlsym动态加载符号,但很遗憾,由于苹果禁止使用这些功能,现在无法使用。我不是.a文件结构的专家,但我有一种感觉,可以通过十六进制编辑器手动完成此操作。让我试试,看看能否帮助您。 - Richard J. Ross III
1个回答

4

看起来你很幸运 - 你仍然可以使用ARM二进制格式重命名符号,只是比objcopy方法更加hacky...

注意:这仅经过了最小限度的测试,我强烈建议在尝试此操作之前备份所有相关库!

还要注意,这仅适用于未使用C++编译器编译的文件!如果在这些文件上使用了C++编译器,它失败。

  1. 首先,你需要一个不错的十六进制编辑器,本例中将使用Hex Fiend
  2. 接下来,你要打开一个库的副本,我们称它为 lib1-renamed.a,并对其进行以下操作:

    • 找到要重命名的符号名称。可以使用 nm 工具找到它,或者如果你知道头文件的名称,那么就可以了。

    • 接下来,你将使用 Hex Fiend 对旧名称(在本例中为 foo)进行文本替换,将其更改为新名称(在本例中为 bar)。这些名称的长度必须相同,否则会破坏二进制文件的偏移量!

      注意:如果有多个函数包含 foo 的名称,可能会出现问题。

  3. 现在,你必须编辑修改过的库的头文件,使用新函数名(bar)替换旧名称。

如果您已正确完成上述三个简单步骤,现在应该能够成功编译和链接两个文件,并调用两种实现。
如果您正在尝试使用通用二进制文件(例如可在模拟器上运行的文件),最好使用`lipo`分离两个二进制文件,在i386/x64二进制文件上使用`objcopy`,然后在ARM二进制文件上使用我的方法,并将它们合并回来使用`lipo`。
†:简单性不保证,也不包含在Richard J. Ross III的超级保修范围内。有关超级保修的更多信息,请立即致电1-800-FREE-WARRANTY。那是1-800-FREE-WARRANTY!

明天测试第一件事,非常感谢你的努力(甚至是你的脚注更多!) :) - Ege Akpinar
1
@EgeAkpinar 别忘了你的免费超级保修! - Richard J. Ross III
好吧,事实证明我不需要保修,因为它的工作非常完美。我之前尝试过重命名,但错过了应该重命名为相同长度的步骤。非常感谢! - Ege Akpinar
7
@AndiDog,感谢您的编辑,但我的幽默风格不会改变。有时人们太过认真对待这个网站,一个好笑话则能让你保持好心情。 - Richard J. Ross III
如果这个能够成功,那就太好了... 我不会复制静态库,因为我正在使用源代码控制。试一试吧!顺便说一句,有没有办法用lipo或其他命令行工具来做这个?我对后期汇编开发/渗透测试等方面了解不够。 - dave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接