如何在Mach-O文件中编辑load命令并在tvOS上成功链接它?

时间:2018-01-17 12:41:03

标签: ios xcode linker tvos mach-o

让我们假设我有一个.a胖库,它是为几种架构而构建的(例如armv7,armv7s,i386,x86_64,arm64)。库是为iOS构建的(其中包含cmd LC_VERSION_MIN_IPHONEOS和6.0版)。例如,当我运行 $ otool -lv 时,我会获得带有此类加载命令的部分:

Load command 1
      cmd LC_VERSION_MIN_IPHONEOS
  cmdsize 16
  version 6.0
      sdk n/a

我想将其替换为:

Load command 1
      cmd LC_VERSION_MIN_TVOS
  cmdsize 16
  version 9.0
      sdk n/a

有人知道我该怎么做或者可以指出一些有用的资源? 我还可以在tvOS上链接修改过的库吗?

1 个答案:

答案 0 :(得分:3)

如果您有权访问源代码,那么最好的解决方案显然是为tvOS重新编译它。

如果您无法访问源代码,那么快速而肮脏的解决方案是在十六进制编辑器中打开库,搜索这些字节(每个目标文件一次):

25000000 10000000 00000600 00000000

并用以下内容替换它们:

2f000000 10000000 00000900 00000000

更稳定的解决方案是编写一个小型C程序来解析和编辑目标文件的标头。在安装了Xcode的Mac上,您可以从<mach-o/loader.h>头文件中获取所需的所有信息(以及有用的注释)。对于其他人,该文件也可以从the XNU source code获得。

迭代所有加载命令的基本思路如下所示,给定一个包含Mach-O的char缓冲区file

struct mach_header_64 *hdr = (struct mach_header_64*)file;
for(struct load_command *cmd = (struct load_command*)(hdr + 1),
                        *end = (struct load_command*)((uintptr_t)cmd + hdr->sizeofcmds);
    cmd < end;
    cmd = (struct load_command*)((uintptr_t)cmd + cmd->cmdsize)
)
{
    // ...
}

现在,出于您的目的,您需要进行迭代,直到找到包含cmd->cmd == LC_VERSION_MIN_IPHONEOS的加载命令,并将其替换为LC_VERSION_MIN_TVOS。您还需要将该加载命令转换为struct version_min_command*,然后定义如下:

struct version_min_command {
    uint32_t cmd;
    uint32_t cmdsize;
    uint32_t version;   /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
    uint32_t sdk;       /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
};

因此,为了获得9.0的版本号,您需要为version分配(9 << 16)的值。

然后保存文件,你就完成了。