Mach-O 符号存根 (IOS)

发布于 2024-12-27 00:04:21 字数 1036 浏览 1 评论 0原文

我试图了解 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 增加了固定金额,但我不明白为什么符号表中每个条目的金额相同。

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

谢谢!

I am trying to understand how Mach-o files work, and have made a good deal of progress with the online resources available (In particular, the Apple page here: http://developer.apple.com/library/mac/#documentation/developertools/conceptual/MachORuntime/Reference/reference.html), but I have hit a roadblock on understanding how symbol stubs work.

Using "otool -l" I see the following section:

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

However when I look at the data from the binary file in a hex editor I see the following 4 bytes repeated again and again:

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

This looks something like a LDR which increases the PC by a fixed amount, but I don't see why the amount is the same for each entry in the symbol table.

If someone can shed light on why this is so, or provide any resources that get this low level, please let me know.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

汹涌人海 2025-01-03 00:04:21

我将描述当前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 中的 dyld_stub_binder 函数,向其传递我所说的“符号信息偏移”值。该值是惰性绑定信息流内的偏移量(由 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. 查找名为“_AudioServicesAddSystemSoundCompletion”的函数
    加载中列出的 dylib 列表中的 dylib 编号 NNNN
    命令。
  2. 查找可执行文件的段号 M(最有可能是 __DATA),
  3. 在偏移量 YYYYY 处写入函数指针。
  4. 跳转到查找到的地址,以便实际函数执行其工作。

写入的地址恰好是_AudioServicesAddSystemSoundCompletion$lazy_ptr 插槽。因此,下次调用 _AudioServicesAddSystemSoundCompletion 时,它将直接跳转到导入的函数,而不需要通过 dyld。

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

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

I will describe the situation with the current iOS, it's somewhat different in the old versions.

The symbol stubs indeed load into the PC a function pointer. For the standard "lazy" (on-demand) imports, the pointer resides in the __lazy_symbol section and initially points to a helper routine in the __stub_helper section, e.g.:

__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

The function dyld_stub_binding_helper is the fist one in the __stub_helper section and essentially is just a trampoline to the dyld_stub_binder function in dyld, passing to it what I call "symbol info offset" value. That value is an offset inside the lazy binding info stream (pointed to by the LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command), which is a sort of bytecode stream with commands for dyld. Typical sequence for a lazy import looks like this:

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()

here dyld would do the following:

  1. look up function named '_AudioServicesAddSystemSoundCompletion' from
    a dylib number NNNN in the list of dylibs listed in the load
    commands.
  2. look up the executable's segment number M (most likely __DATA)
  3. write the function pointer at the offset YYYYY.
  4. jump to the looked up address so that the actual function does its job

The address written to happens to be the _AudioServicesAddSystemSoundCompletion$lazy_ptr slot. So, the next time the _AudioServicesAddSystemSoundCompletion is called, it will jump directly to the imported function, without going via dyld.

N.B.: you should not look at the offset 05fc0 in the file right away. The addr field is the virtual address, you should look up the containing segment command and see at what VA it starts and what is its file offset, then do the math. Usually the __TEXT segment starts at 1000.

However, the actual symbol stubs do look like you pasted, probably you have a fat mach-o with the fat header taking the first 1000 bytes, so the offsets line up.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文