Objective c 在macOS上,是否可以修改已编译动态库的符号名?

Objective c 在macOS上,是否可以修改已编译动态库的符号名?,objective-c,swift,xcode,dylib,Objective C,Swift,Xcode,Dylib,我的macOS Objective-C/Swift应用程序有问题。我使用一个给我带来问题的库,我不知道什么时候会有新版本 从我的发现来看,我使用的一个方法在库的最后一个版本中是固定的,但是这个最新版本在另一个方法中引入了一个bug,这个bug在以前的版本中工作 在考虑一个可能的解决方案时,我认为从理论上讲,可以针对两个库进行链接,并在两个库中都使用,但这当然会导致所有符号被定义两次,并且不会编译 是否可以在两个版本中的一个版本中更改符号名称,并引入前缀之类的内容,以便我可以决定在不同情况下使用哪

我的macOS Objective-C/Swift应用程序有问题。我使用一个给我带来问题的库,我不知道什么时候会有新版本

从我的发现来看,我使用的一个方法在库的最后一个版本中是固定的,但是这个最新版本在另一个方法中引入了一个bug,这个bug在以前的版本中工作

在考虑一个可能的解决方案时,我认为从理论上讲,可以针对两个库进行链接,并在两个库中都使用,但这当然会导致所有符号被定义两次,并且不会编译


是否可以在两个版本中的一个版本中更改符号名称,并引入前缀之类的内容,以便我可以决定在不同情况下使用哪个版本?很抱歉,如果这完全没有意义,可能取决于库的具体实现。

您可以修补符号(只要在十六进制编辑器中搜索字符串并更改一些字节就可以了,只要总长度保持不变),但我认为有一个更优雅的解决方案

Mach Os记录要从哪个库导入的符号,默认情况下在非平面名称空间中运行,即不同库的符号在运行时不会相互冲突。
正如您可能已经观察到的,它们确实在链接时发生碰撞。但在链接时处理事情要比修补二进制文件容易得多

我假设您的两个库具有相同的“安装名称”(如果有疑问,请检查
otool-l your.dylib | fgrep-A2 LC_ID_dylib
)。如果是这种情况,那么您必须重命名其中一个。如果动态库的原始安装名称为
/usr/local/lib/libstuff.dylib
,则将其中一个名称重命名为
/usr/local/lib/libstuff\u alt.dylib
,并对其运行以下命令:

install_name_tool -id /usr/local/lib/libstuff_alt.dylib /usr/local/lib/libstuff_alt.dylib
如果您的库已签名或需要签名,您现在需要重新签名:

codesign -f -s - /usr/local/lib/libstuff_alt.dylib
如果您对安装名称的工作方式感到好奇,请参阅

一旦库的两个版本有了不同的名称,让我们进行一个设置,您可以按照这个设置进行操作。我创建了以下C文件:

a.c

int f(void)
{
    return 10;
}

int g(void)
{
    return 11;
}
int f(void)
{
    return 20;
}

int g(void)
{
    return 21;
}
b.c

int f(void)
{
    return 10;
}

int g(void)
{
    return 11;
}
int f(void)
{
    return 20;
}

int g(void)
{
    return 21;
}
并将它们编译到图书馆:

cc -shared -o liba.dylib a.c -Wall -O3
cc -shared -o libb.dylib b.c -Wall -O3
然后我创建了另一个名为
t.c
的文件,它使用
f()
g()
函数:

#include <stdio.h>

extern int f(void);
extern int g(void);

int main(void)
{
    printf("%d %d\n", f(), g());
    return 0;
}
所以我们要做的是作弊,使用“基于文本的存根文件”,可以用来链接,而不是实际的dylib

xcrun tapi stubify -o liba.tbd liba.dylib
xcrun tapi stubify -o libb.tbd libb.dylib
这将创建文件
liba.tbd
libb.tbd
,如下所示:

--- !tapi-tbd
tbd-version:     4
targets:         [ arm64-macos ]
uuids:
  - target:          arm64-macos
    value:           2AACA829-4039-3B2A-8751-2AB617189F29
flags:           [ not_app_extension_safe ]
install-name:    liba.dylib
current-version: 0
compatibility-version: 0
exports:
  - targets:         [ arm64-macos ]
    symbols:         [ _f, _g ]
...
此时,我们可以从这些文件中删除不需要的符号。在我的示例中,我确保
liba.tbd
只有
[\u f]
,而
libb.tbd
只有
[\u g]
。完成后,我们可以再试一次:

% cc -o t t.c -Wall -O3 -L. -la -lb
% ./t
10 21
就这样

执行此操作时唯一需要注意的是,您需要确保所使用的函数对它们来自的库没有任何类型的内部依赖性,如全局变量