命令太多了? Dyld消息:格式错误的mach-o:加载命令大小

时间:2017-07-04 09:54:10

标签: ios ios9 dyld

一些iOS 9设备似乎崩溃了我从Xcode中的基本崩溃报告中收到的错误消息

  

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

不幸的是,这是我获得的所有信息。我甚至无法在本地调试或复制。 任何人都可以在这里暗示我正确的方向吗?

在更新我的Cocoapods后会发生这种情况,所以我猜其中有一个(或他们的依赖性)行为不端。

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

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

4 个答案:

答案 0 :(得分:5)

我找到了一个能够(至少暂时)为我工作的解决方案 - 但我仍然鼓励每个人提供真正的解决方案和更详细的见解。

反正:

提取二进制文件

  1. Xcode Archive
  2. 导出为IPA
  3. YourApp.ipa重命名为YourApp.zip并解压缩
  4. 导航到子文件夹有效内容以找到您的YourApp.app
  5. 右击& Show Package Contents文件的YourApp.app
  6. 将二进制文件YourApp(无文件扩展名)复制到其他位置
  7. 调查你的机器二进制文件

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

      注意列出了两个体系结构的align,对我来说,这是2 ^ 14(16384)。这似乎是加载命令大小的阈值。

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

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

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

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

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

        如果我错了,请纠正我,我只是假设在这里,我真的很想知道为什么会这样。

        解决问题

        删除框架,直到您处于两个架构的sizeofcmds之下。

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

        幸运的是,这似乎只是iOS9上的问题,因此在接下来的几个月内会失去相关性,但是,我们应该知道我是否正确

        调查意见

        我可以通过插入越来越多的框架来研究对齐是否自动调整,以确定它是否确实存在。

        如果是这样,添加框架也可以解决原始问题 - 不是很好,但至少可以稍微扩展一些。

        旁注

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

答案 1 :(得分:3)

所以这就是问题所在:

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

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

顺便说一下,'对齐'与此无关 - 对齐是指胖(通用)架构切片,并不与Mach-O有任何关系。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

在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的限制。