7

我正在尝试了解 Mach-o 文件的工作原理,并在可用的在线资源方面取得了很大进展(特别是这里的 Apple 页面:http: //developer.apple.com/library/mac/#documentation /developertools/conceptual/MachORuntime/Reference/reference.html),但我在理解符号存根如何工作方面遇到了障碍。

使用“otool -l”我看到以下部分:

Section
  sectname __symbolstub1
   segname __TEXT
      addr 0x00005fc0
      size 0x00000040
    offset 20416
     align 2^2 (4)
    reloff 0
    nreloc 0
     flags 0x80000408

但是,当我在十六进制编辑器中查看二进制文件中的数据时,我看到以下 4 个字节一次又一次地重复:

00005FC0  38 F0 9F E5 38 F0 9F E5  38 F0 9F E5 38 F0 9F E5  88
00005FD0  38 F0 9F E5 38 F0 9F E5  38 F0 9F E5 38 F0 9F E5  88
00005FE0  38 F0 9F E5 38 F0 9F E5  38 F0 9F E5 38 F0 9F E5  88  
00005FF0  38 F0 9F E5 38 F0 9F E5  38 F0 9F E5 38 F0 9F E5  88

这看起来有点像 LDR,它将 PC 增加了固定数量,但我不明白为什么符号表中每个条目的数量都相同。

如果有人可以解释为什么会这样,或者提供任何达到这个低水平的资源,请告诉我。

谢谢!

4

1 回答 1

16

我将描述当前 iOS 的情况,在旧版本中有所不同。

符号存根确实将函数指针加载到 PC 中。对于标准的“惰性”(按需)导入,指针位于__lazy_symbol节中,最初指向节中的帮助程序__stub_helper,例如:

__symbolstub1 _AudioServicesAddSystemSoundCompletion
__symbolstub1 LDR  PC, _AudioServicesAddSystemSoundCompletion$lazy_ptr
__symbolstub1 ; End of function _AudioServicesAddSystemSoundCompletion

__lazy_symbol _AudioServicesAddSystemSoundCompletion$lazy_ptr DCD _AudioServicesAddSystemSoundCompletion$stubHelper

__stub_helper _AudioServicesAddSystemSoundCompletion$stubHelper
__stub_helper LDR R12, =nnn ; symbol info offset in the lazy bind table
__stub_helper B   dyld_stub_binding_helper

该函数dyld_stub_binding_helper是本__stub_helper节中的第一个函数,本质上只是dyld_stub_binderdyld 中函数的蹦床,将我称之为“符号信息偏移”的值传递给它。该值是延迟绑定信息流中的偏移量(由 LC_DYLD_INFO 或 LC_DYLD_INFO_ONLY 加载命令指向),这是一种带有 dyld 命令的字节码流。延迟导入的典型顺序如下所示:

72: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(M, 0xYYYYY)
19: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(NNNN)
40: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, '_AudioServicesAddSystemSoundCompletion')
90: BIND_OPCODE_DO_BIND()

这里 dyld 将执行以下操作:

  1. 从加载命令中列出的 dylib 列表中的 dylib 编号 NNNN 中查找名为“_AudioServicesAddSystemSoundCompletion”的函数。
  2. 查找可执行文件的段号 M(很可能是 __DATA)
  3. 在偏移量 YYYYY 处写入函数指针。
  4. 跳转到查找的地址,以便实际函数完成其工作

写入的地址恰好是_AudioServicesAddSystemSoundCompletion$lazy_ptr插槽。所以,下次_AudioServicesAddSystemSoundCompletion调用时,会直接跳转到导入的函数,不经过dyld。

注意:您不应该立即查看文件中的偏移量 05fc0。该addr字段是虚拟地址,您应该查找包含段命令并查看它从哪个 VA 开始以及它的文件偏移量是多少,然后进行数学运算。通常 __TEXT 段从 1000 开始。

但是,实际的符号存根看起来确实像您粘贴的那样,可能您有一个 fat mach-o,其中 fat header 占用前 1000 个字节,因此偏移量对齐。

于 2012-01-12T14:20:51.227 回答