【问题标题】:Too many commands? Dyld Message: malformed mach-o: load commands size命令太多? Dyld 消息:格式错误的 mach-o:加载命令大小
【发布时间】:2017-12-07 17:35:52
【问题描述】:

某些 iOS 9 设备似乎因我从 Xcode 中非常基本的崩溃报告中收到的错误消息而崩溃

dyld:格式错误的 mach-o:加载命令大小 (16464) > 16384

不幸的是,这就是我得到的所有信息。我什至无法在本地调试或重现。 谁能在这里提示我正确的方向?

它发生在更新我的 Cocoapods 之后,所以我猜其中有一个(或它们的依赖项)行为不端。

在对我的 mach-O 二进制文件进行一些调查后,我发现 sizeofcmds 确实是 16464。 如果我理解正确的话,加载命令的大小限制似乎是 16384,有人可以确认吗?

这是否意味着我应该删除 dylib 并且一切都应该没问题?

【问题讨论】:

  • 你能在这里列出依赖关系吗?
  • 本周也遇到了这个问题。讨厌的问题。奇怪的是,我发现其他提到的限制是 32768(两倍)。
  • 让我们一起解决这个问题。在您导出的可执行文件上运行 otool -l 并查看您的体系结构的 sizeofcmds。另外请告诉我您使用的架构,我使用 armv7 和 arm64(对于军队 64,命令的大小超过了“限制”
  • 是的,我查看了 otool 的输出,它与 dyld 的错误消息相匹配。我刚刚注意到您在谈论设备,而我正在模拟器上处理它(在 Sierra 上运行),所以我的拱门是 x86-64。不过,我认为这是 iOS 9 上的 dyld,因为 10.x 设备和 sim 工作正常。仍然不确定该怎么做。一位同事一直在调查,但我不知道她是否发现了什么。
  • 一些加载命令包含调试器的数据,您可以在链接器中尽量减少发出的调试内容。验证二进制文件的便捷工具是MachOView。您还可以查看我在LCs 的最小集合上的帖子,这是二进制文件在此处工作所必需的:stackoverflow.com/a/42399119/5329717

标签: ios ios9 dyld


【解决方案1】:

在 WWDC18 上,我找到了一位正在开发 dyld 的 Apple 工程师。这是他不得不说的:

  • Dyld 代码可从https://opensource.apple.com 下载(我们特有的代码可以在 macOS 10.12 中找到)
  • 对于 iOS 9,加载命令的最大大小确实是 16k 也就是 1 个内存页面(没有办法!这是操作系统本身强加的。客户服务告诉人们更新到 iOS 10(所有运行 iOS 9 的设备都可以,除了 iPhone 4S)将是可行的。)
  • 自 iOS 10 起,命令的最大大小为 32k
  • 加载命令的大部分大小由框架的字符串(路径)决定(使用命令otool -L 来查看它们

可能的解决方案:

  • 使用更少的库(这是我们目前的 goto 解决方案,但我们将改为使用伞式库(见下文))
  • 缩短名称(可能会搞砸可可豆荚的标题查找,可能会在 Xcode 构建过程中使用头部映射来修复该问题 → WWDC18 会议“Xcode 构建过程的幕后”中可能会提供更多(高级)信息)
  • 尝试为图书馆建立静态档案(不应该有动态资源,否则会进行复制阶段并找出资源在哪里)
  • 构建重新导出其他框架(伞形框架)的框架。使用-reexport-l 作为链接器标志(不经常这样做)→ 会在启动应用程序时产生一些运行时开销,也会使用更多内存(man ld → 有关重新导出的信息)

工程师建议通过bugreport.apple.com 提交错误报告,因为将来甚至有可能达到 32k 的限制。

【讨论】:

    【解决方案2】:

    在查看 otool -l 的结果后,我能够为我的团队解决此问题。结果我们的框架搜索路径 5x 中包含相同的目录,导致我们的 dylibs 被添加为 rpaths 5x。

    【讨论】:

      【解决方案3】:

      那么问题来了:

      Mach-O 标头大小预计为 16k(针对平台的页面大小进行了优化)。在 rachit 的参考资料中,它基本上是一样的,但限制是 32K。两者都是正确的,因为这是加载程序 dyld 的硬限制。

      加载命令的总大小超过了这个最大大小。删除框架和库对您有用,因为这会删除 LC_LOAD_DYLIB 命令(而且,您没有理由需要这么多框架)。不要删除框架,而是从核心框架开始从头开始构建您的应用程序,并在遇到链接器错误时添加。

      顺便说一句,“对齐”与此无关 - 对齐是指胖(通用)架构切片,与 Mach-O 没有任何关系。

      【讨论】:

      • 感谢您的解释。我的应用程序具有相当大的规模和复杂性,我们使用的每个框架都是相关的。它汇总了多达 89 个导入的 dyllib 或框架。我真的无法想象这太过分了,或者是吗?
      • 即使是比你的应用程序更复杂的跳板,也有 140 多个框架,并且适合标题。你能在你的 Mach-O 上提供“jtool -l”的输出吗?
      【解决方案4】:

      我找到了一个(至少暂时)适合我的解决方案 - 但我仍然鼓励大家提供真正的解决方案和更详细的见解。

      无论如何:

      解压你的二进制文件

      1. Xcode 存档
      2. 导出为 IPA
      3. YourApp.ipa 重命名为YourApp.zip 并提取
      4. 导航到子文件夹有效负载以找到您的YourApp.app
      5. 在您的YourApp.app 文件中单击鼠标右键和Show Package Contents
      6. 将二进制文件YourApp(无文件扩展名)复制到其他位置

      调查你的 mach-o 二进制文件

      1. 在您的二进制文件上运行 otool -f

      请注意,这两种架构的 align 都已列出,对我来说,这表示 2^14 (16384)。这似乎是加载命令大小的阈值。

      1. 在您的二进制文件上运行 otool -l

      您会看到列出了不同的架构及其加载命令 - 以及它们的 sizeofcmds(命令大小)。

      现在有趣的是: 对于 arm64,sizeofcmds (16464) 大于 align (16384),而对于 armv7 则不是。

      现在我还没有找到足够的文档,但我认为 align 表示加载命令大小不应达到的阈值。而且它会自动调整(因为我们的应用程序中肯定没有那么多框架,所以必须有更多的应用程序)。

      所以我猜这个错误来自这种不太可能的情况,sizeofcmds 在架构之间是不同的,并且其中一个实际上是有效的(因此对齐不会自动调整)。

      如果我错了,请纠正我,我只是在这里假设,我真的很想了解为什么会发生这种情况。

      解决问题

      删除框架,直到您在两种架构的 sizeofcmds 下。

      我知道这是不可扩展的,我们很幸运(也很愚蠢),我们仍然有一个几乎没有使用过的框架,我们可以轻松删除。

      幸运的是,这似乎只是 iOS9 上的一个问题,因此在接下来的几个月中将失去相关性,不过,我们应该看看我是否正确

      调查思路

      我假设对齐是自动调整的,可以通过放入越来越多的框架来研究它是否真的这样做。

      如果是这样,添加框架也可以解决最初的问题 - 不是很好,但至少可扩展性更高。

      旁注

      我觉得我对这个问题的根源没有足够的了解,而且我有很多假设。 虽然我的解决方案有效,但我真的希望您也能对此进行调查并给出更好的答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-05
        • 1970-01-01
        • 2021-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-18
        • 1970-01-01
        相关资源
        最近更新 更多