Mach-O可执行文件的__LINKEDIT部分可以移动吗

时间:2019-05-02 12:53:14

标签: mach-o

在一个Mach-O可执行文件中,我试图使用本地工具增加__LLVM段之前的__LINKEDIT段的大小。我正在考虑两种策略:(a)将__LLVM段移到__LINKEDIT段之后,产生一个不是ld会创建的文件(现在的间隙和段地址乱序), (b)移动__LINKEDIT段,以调整其前面的__LLVM段的大小。我需要将结果接受下游处理,例如生成.ipa文件或发送到App Store。

这个问题是关于我的假设以及这些方法的可行性。具体来说,每种可能导致失败的潜在陷阱是什么?

我实现了第一种方法(a),这是segedit的-extract选项所理解的,但是其-replace选项却抱怨这些段是乱序的。我将新段添加到文件中,并在相应的load命令中更新地址和长度值以引用此新段数据(文件和目标内存中都包含)。只要其他下游处理将接受结果(仍在检查;例如,任何本地签名都可能无效),就可以了。

第二种方法(b)看起来更简洁,只要没有__LINKEDIT段中的 引用,我猜它包含链接信息(符号表等),而不是码)。我还没有尝试过,尽管似乎已经断定segedit将对结果感到满意,这可能表明其他处理也可能会更快乐。仅仅由于移动此段,可能存在任何无效的引用吗?我猜想我将不得不更新更多的加载命令(它们似乎引用到__LINKEDIT段中),我没有检查过,但这应该很简单。

编辑:用“段”(在答案中提到)代替了我对“节”的混淆使用。

添加:上下文是我无法控制生成原始可执行文件的地方。我需要对其进行后处理,本质上执行一个“ segedit -replace”过程,其中该段中的一个部分将替换为一个大于先前分配该段的空间的部分。

运行中澄清的问题:从答案看来,移动__LINKEDIT段将破坏它。只能通过调整加载命令(例如LC_DYLD_INFO_ONLY,LC_LOAD_DYLINKER,LC_LOAD_DYLIB)来解决此问题,而不能调整任何段中的数据吗?我还不熟悉这些加载命令,并且想知道是否要执行此操作。

2 个答案:

答案 0 :(得分:1)

因此,基本上,这些段和节描述了物理文件如何映射到虚拟内存。 正如我在答案的上一个迭代中提到的那样,细分顺序存在局限性:

  1. __TEXT部分必须从可执行物理文件偏移量0开始
  2. __LINKEDIT部分必须从物理文件偏移0开始
  3. __LINKEDIT的文件偏移量+文件大小应等于物理可执行文件的大小(这意味着__LINKEDIT是最后一个段)。否则,代码签名将无法正常工作。

__DYLD_INFO_ONLY包含dyld的文件偏移量,用于加载以下内容的绑定操作码

  • 变基
  • 负载绑定
  • 弱绑定
  • 惰性绑定
  • 导出

对于每种类型,__DYLD_INFO_ONLY中都有文件偏移和大小条目,用于描述与__LINKEDIT匹配的文件中的数据(在“常规” ld链接的可执行文件中)。 __DYLD_INFO_ONLY不直接使用__LINKEDIT中的任何分段和节信息,文件的偏移量和大小就足够了。

编辑也如@kirelagin答案here中所述
“显然,从10.12 Sierra开始的dyld新版本执行的检查是以前版本没有执行:确保LC_SYMTAB符号表完全在__LINKEDIT段内。”

我假设由于您想增加前__LLVM段的大小,因此您还希望文件本身包含一些额外的数据。通常,__LINKEDIT描述的数据(即不是段和节本身,而是实际数据)不会占用其100%的空间,因此可以对其进行修改以开始“以后”并占用更少的空间。

乔纳森·莱文(Jonathan Levin)称为jtool的工具可能可以为您做到这一点。

答案 1 :(得分:1)

我知道这是一个老问题,但是我在解决另一个problem的同时解决了这个问题。

  1. 定义幻灯片数量,该数量必须与页面对齐,因此我选择0x4000。
    1. 将滑动量添加到相关的加载命令中,包括但不限于:
      • __ LINKEDIT段(duh)
      • dyld_info_command
      • symtab_command
      • dysymtab_command
      • linkedit_data_commands
    2. 物理上移动文件中的__LINKEDIT。