MachO动态库绑定过程详解

动态库绑定过程详解

首先动态库绑定分为lazy bind 和no_lazy_bind,
lazy bind 主要用于模块外部的函数调用,由于调用者并不是每个函数都调用,延迟绑定有利于提高动态库的加载速度
no_lazy_bind: 主要用于模块外部调用一些全局的变量,由于通常暴露的外部变量较少,所以在启动时绑定,但少数函数除外,例如dyld_stub_binder。

no_lazy_bind 会在程序启动之后又dynamic_link_edit完成,想要了解可以看看动态链接库的原理。

这里主要分析一下 lazy bind过程。

先写一段demo

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [[DemoFramework new] codingLife];
    [[GoodBoy new] xuanGao];
    
    helloWorld();
    
}


@end

其中helloWorld是动态库一个函数,反编译一下

                                       ; 
                                       ; Section __text
                                       ; 
                                       ; Range 0x100001680 - 0x100001a33 (947 bytes)
                                       ; File offset 5760 (947 bytes)
                                       ; Flags : 0x80000400
                                       ; 
                     -[ViewController viewDidLoad]:
0000000100001680         push       rbp                                         ; Objective C Implementation defined at 0x1000030d8 (instance), XREF=0x1000000d0
0000000100001681         mov        rbp, rsp
0000000100001684         sub        rsp, 0x30
0000000100001688         lea        rax, qword [ss:rbp+var_20]
000000010000168c         mov        qword [ss:rbp+var_8], rdi
0000000100001690         mov        qword [ss:rbp+var_10], rsi
0000000100001694         mov        rsi, qword [ss:rbp+var_8]
0000000100001698         mov        qword [ss:rbp+var_20], rsi
000000010000169c         mov        rsi, qword [ds:0x100003cb0]                 ; 0x100003cb0
00000001000016a3         mov        qword [ss:rbp+var_18], rsi
00000001000016a7         mov        rsi, qword [ds:0x100003c70]                 ; @selector(viewDidLoad), argument "selector" for method imp___stubs__objc_msgSendSuper2
00000001000016ae         mov        rdi, rax                                    ; argument "super" for method imp___stubs__objc_msgSendSuper2
00000001000016b1         call       imp___stubs__objc_msgSendSuper2
00000001000016b6         mov        rax, qword [ds:objc_cls_ref_DemoFramework]  ; objc_cls_ref_DemoFramework
00000001000016bd         mov        rsi, qword [ds:0x100003c78]                 ; @selector(new), argument "selector" for method imp___got__objc_msgSend
00000001000016c4         mov        rdi, rax
00000001000016c7         call       qword [ds:imp___got__objc_msgSend]
00000001000016cd         mov        rsi, qword [ds:0x100003c80]                 ; @selector(codingLife), argument "selector" for method imp___got__objc_msgSend
00000001000016d4         mov        rdi, rax                                    ; argument "instance" for method imp___got__objc_msgSend
00000001000016d7         mov        qword [ss:rbp+var_28], rax
00000001000016db         call       qword [ds:imp___got__objc_msgSend]
00000001000016e1         mov        rax, qword [ss:rbp+var_28]
00000001000016e5         mov        rdi, rax
00000001000016e8         call       qword [ds:imp___got__objc_release]
00000001000016ee         mov        rax, qword [ds:objc_cls_ref_GoodBoy]        ; objc_cls_ref_GoodBoy
00000001000016f5         mov        rsi, qword [ds:0x100003c78]                 ; @selector(new), argument "selector" for method imp___got__objc_msgSend
00000001000016fc         mov        rdi, rax
00000001000016ff         call       qword [ds:imp___got__objc_msgSend]
0000000100001705         mov        rsi, qword [ds:0x100003c88]                 ; @selector(xuanGao), argument "selector" for method imp___got__objc_msgSend
000000010000170c         mov        rdi, rax                                    ; argument "instance" for method imp___got__objc_msgSend
000000010000170f         mov        qword [ss:rbp+var_30], rax
0000000100001713         call       qword [ds:imp___got__objc_msgSend]
0000000100001719         mov        rax, qword [ss:rbp+var_30]
000000010000171d         mov        rdi, rax
0000000100001720         call       qword [ds:imp___got__objc_release]
0000000100001726         mov        al, 0x0
0000000100001728         call       imp___stubs__helloWorld
000000010000172d         add        rsp, 0x30
0000000100001731         pop        rbp
0000000100001732         ret        
                        ; endp

跟踪一下 call imp___stubs__helloWorld


                                       ; 
                                       ; Section __stubs
                                       ; 
                                       ; Range 0x100001a34 - 0x100001a64 (48 bytes)
                                       ; File offset 6708 (48 bytes)
                                       ; Flags : 0x80000408
                                       ; 
                     imp___stubs__NSStringFromClass:
0000000100001a34         jmp        qword [ds:imp___la_symbol_ptr__NSStringFromClass] ; XREF=0x100000120, _main+74
                        ; endp


================ B E G I N N I N G   O F   P R O C E D U R E ================



                     imp___stubs__UIApplicationMain:
0000000100001a3a         jmp        qword [ds:imp___la_symbol_ptr__UIApplicationMain] ; XREF=_main+107
                        ; endp


================ B E G I N N I N G   O F   P R O C E D U R E ================



                     imp___stubs__helloWorld:
0000000100001a40         jmp        qword [ds:imp___la_symbol_ptr__helloWorld]  ; XREF=-[ViewController viewDidLoad]+168
                        ; endp

这是一个__stubs段,需要lazy_bind的函数都可以在这个段找到。

                                       ; 
                                       ; Section __la_symbol_ptr
                                       ; 
                                       ; Range 0x100003020 - 0x100003060 (64 bytes)
                                       ; File offset 12320 (64 bytes)
                                       ; Flags : 0x00000007
                                       ; 
                     imp___la_symbol_ptr__NSStringFromClass:
0000000100003020         dq         0x0000000100001a7e                          ; XREF=0x100000488, imp___stubs__NSStringFromClass
                     imp___la_symbol_ptr__UIApplicationMain:
0000000100003028         dq         0x0000000100001aba                          ; XREF=imp___stubs__UIApplicationMain
                     imp___la_symbol_ptr__helloWorld:
0000000100003030         dq         0x0000000100001a74                          ; XREF=imp___stubs__helloWorld
                     imp___la_symbol_ptr__objc_autoreleasePoolPop:
0000000100003038         dq         0x0000000100001a88                          ; XREF=imp___stubs__objc_autoreleasePoolPop
                     imp___la_symbol_ptr__objc_autoreleasePoolPush:
0000000100003040         dq         0x0000000100001a92                          ; XREF=imp___stubs__objc_autoreleasePoolPush
                     imp___la_symbol_ptr__objc_msgSendSuper2:
0000000100003048         dq         0x0000000100001a9c                          ; XREF=imp___stubs__objc_msgSendSuper2
                     imp___la_symbol_ptr__objc_retainAutoreleasedReturnValue:
0000000100003050         dq         0x0000000100001aa6                          ; XREF=imp___stubs__objc_retainAutoreleasedReturnValue
                     imp___la_symbol_ptr__objc_storeStrong:
0000000100003058         dq         0x0000000100001ab0                          ; XREF=imp___stubs__objc_storeStrong
                                       ; 
       

__la_symbol_ptr 段,这里可以看到 imp___stubs__helloWorld = 0x0000000100001a74

所以这段代码最终会跳转到 0x0000000100001a74

                                       ; 
                                       ; Section __stub_helper
                                       ; 
                                       ; Range 0x100001a64 - 0x100001ac4 (96 bytes)
                                       ; File offset 6756 (96 bytes)
                                       ; Flags : 0x80000400
                                       ; 
0000000100001a64         lea        r11, qword [ds:0x100003008]                 ; 0x100003008 (imp___nl_symbol_ptr_dyld_stub_binder + 0x8), XREF=0x100000170, 0x100001a79, 0x100001a83, 0x100001a8d, 0x100001a97, 0x100001aa1, 0x100001aab, 0x100001ab5, 0x100001abf
0000000100001a6b         push       r11
0000000100001a6d         jmp        qword [ds:imp___nl_symbol_ptr_dyld_stub_binder]
0000000100001a73         nop        
0000000100001a74         push       0x32                                        ; XREF=imp___la_symbol_ptr__helloWorld
0000000100001a79         jmp        0x100001a64
0000000100001a7e         push       0x0                                         ; XREF=imp___la_symbol_ptr__NSStringFromClass
0000000100001a83         jmp        0x100001a64
0000000100001a88         push       0x44                                        ; XREF=imp___la_symbol_ptr__objc_autoreleasePoolPop
0000000100001a8d         jmp        0x100001a64
0000000100001a92         push       0x63                                        ; XREF=imp___la_symbol_ptr__objc_autoreleasePoolPush
0000000100001a97         jmp        0x100001a64
0000000100001a9c         push       0x83                                        ; XREF=imp___la_symbol_ptr__objc_msgSendSuper2
0000000100001aa1         jmp        0x100001a64
0000000100001aa6         push       0x9d                                        ; XREF=imp___la_symbol_ptr__objc_retainAutoreleasedReturnValue
0000000100001aab         jmp        0x100001a64
0000000100001ab0         push       0xc7                                        ; XREF=imp___la_symbol_ptr__objc_storeStrong
0000000100001ab5         jmp        0x100001a64
0000000100001aba         push       0x19                                        ; XREF=imp___la_symbol_ptr__UIApplicationMain
0000000100001abf         jmp        0x100001a64

这一段是核心代码

0000000100001a64         lea        r11, qword [ds:0x100003008]                 ; 0x100003008 (imp___nl_symbol_ptr_dyld_stub_binder + 0x8), XREF=0x100000170, 0x100001a79, 0x100001a83, 0x100001a8d, 0x100001a97, 0x100001aa1, 0x100001aab, 0x100001ab5, 0x100001abf
0000000100001a6b         push       r11
0000000100001a6d         jmp        qword [ds:imp___nl_symbol_ptr_dyld_stub_binder]
0000000100001a73         nop        
0000000100001a74         push       0x32                                        ; XREF=imp___la_symbol_ptr__helloWorld
0000000100001a79         jmp        0x100001a64

仔细分析一下其实执行顺序是这样的

0000000100001a74         push       0x32  
0000000100001a64         lea        r11, qword [ds:0x100003008]                 ; 0x100003008 (imp___nl_symbol_ptr_dyld_stub_binder + 0x8), XREF=0x100000170, 0x100001a79, 0x100001a83, 0x100001a8d, 0x100001a97, 0x100001aa1, 0x100001aab, 0x100001ab5, 0x100001abf
0000000100001a6b         push       r11
0000000100001a6d         jmp        qword [ds:imp___nl_symbol_ptr_dyld_stub_binder]

可以确定的是imp___nl_symbol_ptr_dyld_stub_binder 需要两个参数一个0x32, 一个是 qword [ds:0x100003008] 内存指针,看一下这块内存

                                   ; Section __nl_symbol_ptr
                                       ; 
                                       ; Range 0x100003000 - 0x100003010 (16 bytes)
                                       ; File offset 12288 (16 bytes)
                                       ; Flags : 0x00000006
                                       ; 
                     imp___nl_symbol_ptr_dyld_stub_binder:
0000000100003000         dq         dyld_stub_binder                            ; XREF=0x100000398, 0x1000003e8, 0x100001a6d
0000000100003008         dq         0x0000000000000000                          ; XREF=0x100001a64

大胆推测一下其中一个可能是偏移地址一个是基地址,之后可能需要花些时间研究一下。

整个逻辑应该是 偏移地址 + 基地址, 如果该快内存有值的话,那么就不需要查找真正的函数地址,否则则需要根据符号表去查找函数表的地址,然后写入该内存。
在回过头追踪下这行指令:


[ds:imp___nl_symbol_ptr_dyld_stub_binder]

;  imp___nl_symbol_ptr_dyld_stub_binder =  0000000100003000

屏幕快照 2019-10-30 下午5.36.18.png

dyld_stub_binder 没有被初始化,因为它也是动态库函数,只有在加载的时候才会初始化。

静态分析 可执行文件结构

加载命令 加载动态执行库、加载动态链接库
关键函数 dyld_stub_binder

自举: 动态链接库也是一个动态库,在加载动态库时第一件事情就是加载动态链接库,所以可怜的动态链接库只能自己加载自己,别的动态库可以通过链接器实行动态加载,这种行为称为自举。 所以它是一个有点特殊的动态链接库

follow 动态绑定source code 梳理流程

.got global offset table
._no_lazy_symbol
._lazy_symbol
.dynamic_symbol_table
got 段 global offset table
_no_lazy_symbol
_lazy_symbol

dynamic_symbol_table

你可能感兴趣的:(MachO动态库绑定过程详解)