iOS 的非懒加载符号会在dyld加载时就绑定真实的值。而懒加载符号不会。只在第一次调用它是才会绑定真实的地址。
通过一个例子 根据 Mach-O文件去了解。

第一次调用这个printf函数

会找到在Section64(Text,__stub)上的地址。找到对应的符号,printf。

然后通过 si 命令继续执行。看到跳转到 0x10003eb2的地址,就是 上述 stub中的偏移地址加上基地址。然后跳转到0x100003efa的地址。根据stub 从 la_symbol_ptr 中找到对应的指针。


带上偏移地址,跳转到 stub_helper 的头部

进入执行,会跳转到 0x3eb8 。在 Section64(Text, __stub_helper) 对应的方法执行。

然后继续执行,会跳转到 libdyld.dylib`dyld_stub_binder: 的方法。去进行方法绑定

在dyld_stub_binder 中会找到并跳转执行 libsystem_c.dylib`printf

当第二次执行 printf 方法时。就会直接找到 printf的地址

总结
第一次调用
- 通过 __stubs 找到 __la_symbol_prt 中的指针
- 带上偏移地址执行 _stub_helper 头部
- 调用 dyld_stub_binder 然后再调用 _dyld_fast_stub_entry 执行绑定。(通过 debug -> debug workflow -> allways show disassemblys 断点查看)
- 从lazy Bindding info 定位真实符号模块并写会 _la_symbol_ptr
第二次调用
- 直接根据 _la_symbol_ptr 已绑定的符号跳转
网友评论