1、本地符号和全局符号
1.1、本地和全局方法
// 全局符号!暴露给外界使用
void test() {
}
// 本地符号
static void test1() {
printf("123");
}
int main(int argc, char * argv[]) {
test();
test1();
return 0;
}
查看mach-o文件命令
objdump -macho -t Demo
000000010000600c l F __TEXT,__text -[ViewController viewDidLoad]
0000000100006050 l F __TEXT,__text -[AppDelegate application:didFinishLaunchingWithOptions:]
00000001000060c8 l F __TEXT,__text -[AppDelegate application:configurationForConnectingSceneSession:options:]
00000001000061b8 l F __TEXT,__text -[AppDelegate application:didDiscardSceneSessions:]
0000000100006264 l F __TEXT,__text _test1
...
000000010000d450 g O __DATA,__objc_data _OBJC_CLASS_$_AppDelegate
000000010000d4a0 g O __DATA,__objc_data _OBJC_CLASS_$_SceneDelegate
000000010000d3d8 g O __DATA,__objc_data _OBJC_CLASS_$_ViewController
000000010000d428 g O __DATA,__objc_data _OBJC_METACLASS_$_AppDelegate
000000010000d478 g O __DATA,__objc_data _OBJC_METACLASS_$_SceneDelegate
000000010000d400 g O __DATA,__objc_data _OBJC_METACLASS_$_ViewController
0000000100000000 g F __TEXT,__text __mh_execute_header
000000010000622c g F __TEXT,__text _main
0000000100006228 g F __TEXT,__text _test
1.2、从终端执行的结果看出test为全局方法(g),test1位本地方法(l)
通过MachOView查看
Symbol Table包含所有的符号表(本地、全局、间接)
Dynamic Symbol Table只包含间接符号表
2、外部符号绑定过程过程
懒加载符号表都是执行本地的符号绑定,然后再执行具体的函数
执行OC代码
- (void)viewDidLoad {
[super viewDidLoad];
// 间接符号
NSLog(@"打印第一个代码");
// bl > 桩!(去符号表里面的地址指向) > 符号表
// bl > 符号表(里面保存的地址!)
NSLog(@"打印第二个代码");
}
2.1、执行第一次NSLog
1、NSLog汇编代码
程序的起始地址:0x000000010434c000
NSLog的汇编地址:0x1043524a0
0x64A0(偏移地址)= 0x1043524a0-0x000000010434c000
2、通过0x64A0查找到桩
Section64(__TEXT,__stubs)表
3、通过懒加载表找到汇编的执行代码地址0x6554
4、具体的桩查找汇编执行过程
5、dyld_stub_binder地址
dyld_stub_binder的地址是程序默认偏移0x8000
2.2、执行第二次NSLog
第二次执行NSLog的时候通过桩直接跳转到函数的真实地址
2.3、执行过程总结
1、外部函数调用是执行桩里面的代码 TEXT, stubs
通过懒加载符号表里面的地址去执行
2、懒加载符号表里面默认保存的是寻找binder的代码
binder函数是在非懒加载符号表里面(程序运行就绑定好了)
3、加载完成后修改懒加载符号表为真实的跳转地址。