如何在 Mach-O 文件中编辑加载命令并在 tvOS 上成功 link 它?

How to edit load command in Mach-O file and successfully link it on tvOS?

假设我有一个 .a fat 库,它是为多种架构构建的(例如 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

有谁知道我该怎么做或者可以指出一些有用的资源吗? 我还能 link 修改 tvOS 上的库吗?

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

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

25000000 10000000 00000600 00000000

并用这些替换它们:

2f000000 10000000 00000900 00000000

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

获得

迭代所有加载命令的基本思想如下所示,给定一个包含 Mach-O:

的字符缓冲区 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) 的值。

然后将文件保存回来就大功告成了。