美文网首页程序的加载与链接
程序的加载与链接(六) 动态库 lazy bind

程序的加载与链接(六) 动态库 lazy bind

作者: 狼性刀锋 | 来源:发表于2019-11-04 15:56 被阅读0次

简述

看了很久的关于动态库链接加载的知识,但对其中的一些细节一直似懂非懂的,所以决定实践一下加深一下印象。本文主要介绍动态库符号的lazy bind 过程。

Demo

先实现一个简单的动态库

// .h
int add(int a,int b);
int sub(int a,int b);

// .c 
#import "*.h"

int add(int a,int b) {

    return a + b;
}

int sub(int a,int b) {
 
    return a - b;
}

实现一个简单的app

// ViewController.m
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    int result = add(3, 4);
//    void * addPoint = add;
//    void * subPoint = sub;
    
    result = sub(3, 4);
    
    NSLog(@"********");
    
    
}


传送门

符号表

屏幕快照 2019-11-04 上午11.17.37.png
  • 符号名: _add
  • 类型: 未定义
  • 来源: adder lib

间接符号表

所有需要间接访问的符号都存放在这里,包括lazy和no_lazy符号,类似于重定位表的格式


屏幕快照 2019-11-04 上午11.18.30.png
  • 符号名
  • 段名
  • 地址

lazy bind 符号表

存放着lazy bind 符号地址信息, 例如: _add 符号地址0x100003038, 它的value 是多少呢?0x100001a80

屏幕快照 2019-11-04 下午3.57.35.png

0x100001a80 指向的是一段汇编代码:

0000000100001a70         lea        r11, qword [ds:0x100003008]                 ; 0x100003008 (imp___nl_symbol_ptr_dyld_stub_binder + 0x8), XREF=0x100000170, 0x100001a85, 0x100001a8f, 0x100001a99, 0x100001aa3, 0x100001aad, 0x100001ab7, 0x100001ac1, 0x100001acb, 0x100001ad5, 0x100001adf
0000000100001a77         push       r11
0000000100001a79         jmp        qword [ds:imp___nl_symbol_ptr_dyld_stub_binder]
0000000100001a7f         nop        
0000000100001a80         push       0x3f                                        ; XREF=imp___la_symbol_ptr__add
0000000100001a85         jmp        0x100001a70

整理一下就是:

0000000100001a80         push       0x3f    
0000000100001a70         lea        r11, qword [ds:0x100003008]                 ; 0x100003008 (imp___nl_symbol_ptr_dyld_stub_binder + 0x8), XREF=0x100000170, 0x100001a85, 0x100001a8f, 0x100001a99, 0x100001aa3, 0x100001aad, 0x100001ab7, 0x100001ac1, 0x100001acb, 0x100001ad5, 0x100001adf
0000000100001a77         push       r11
0000000100001a79         jmp        qword [ds:imp___nl_symbol_ptr_dyld_stub_binder]

稍后再解释它的作用

验证lazy bind

我现在要校验一下add函数调用之后, _add 符号的间接地址指针是否被修改了

  • 程序启动前main函数地址: 0x100001740
  • 运行时地址main函数地址: 0x1023c6740
  • 因此得到全局偏移量 offset: 0x1023c6740 - 0x100001740
  • 计算得到_add 符号间接寻址地址: offset + 0x100003038 = 0x1023c8038
  • 查看 0x1023c8038 内存: 0x00000001026b8f40


    屏幕快照 2019-11-04 下午2.39.16.png
  • log add 函数地址: 0x00000001026b8f40
屏幕快照 2019-11-04 下午2.40.41.png

这样就成功校验了,lazy bind 理论是正确的

: 观察完整的lazy bind 其实还有一步,就是在没有调用add符号之前,查看间接符号的值, 这个值等于 0x100001a80 + offset, 即指向上面提到的那段汇编代码

lazy bind 过程

  1. 调用 stub_add 函数


    屏幕快照 2019-11-04 下午3.14.31.png
  1. stub_add 会跳转到 间接符号表所指向的地址(间接寻址的关键指令)


    屏幕快照 2019-11-04 下午3.15.30.png
屏幕快照 2019-11-04 上午11.19.03.png

此时 :imp___la_symbol_ptr__add 指向的就是上述的那段汇编代码的地址, 静态地址: 0x100001a80 ,动态地址 : 0x100001a80 + offset

下面分别使用MachOView 和 Hopper disassembler 分析一下source code

屏幕快照 2019-11-04 下午3.17.51.png 屏幕快照 2019-11-04 下午3.19.41.png

imp___nl_symbol_ptr_dyld_stub_binder 所处的section:


屏幕快照 2019-11-04 下午4.32.06.png

该段代码最终会调用 imp___nl_symbol_ptr_dyld_stub_binder 函数,由动态链接库dyld.lib的stub_binde函数完成符号绑定操作。 imp___nl_symbol_ptr_dyld_stub_binder 需要两个参数

  • lazy binder point address: 0x100003008
  • symbol flag: 主要靠这个识别是哪个函数需要bind,至于为什么是0x3f 具体是怎么编码的还没研究过

imp___nl_symbol_ptr_dyld_stub_binder 属于no_lazy_symbol point,这个在程序启动后就已经初始化完毕,它指向dyld.lib 的 stub_binder 函数地址, stub_binder完成查找_add函数的地址,并且写入间接符号表中,最终写入地址( 0x100001a80 + offset), 之后就不再需要绑定了

  • 第一次调用add函数: imp___la_symbol_ptr__add 指向 stub_bind 代码块,触发bind操作
  • 第二次调用add函数: imp___la_symbol_ptr__add 指向add函数真实地址,直接调用add函数

总结

程序加载过程

  1. LC_SEGMENT_64 : 加载代码段、数据段
  2. LC_LOAD_DYLINKER: 加载动态库链接器
  3. LC_LOAD_DYLIB: 加载动态库
  4. 完成 no lazy bind
  5. 程序启动后, 在第一调用动态库函数时完成 lazy bind 操作

相关文章

  • 程序的加载与链接(六) 动态库 lazy bind

    简述 看了很久的关于动态库链接加载的知识,但对其中的一些细节一直似懂非懂的,所以决定实践一下加深一下印象。本文主要...

  • MachO动态库绑定过程详解

    动态库绑定过程详解 首先动态库绑定分为lazy bind 和no_lazy_bind,lazy bind 主要用于...

  • 程序的加载与链接(七) 动态库 no lazy bind

    不同于静态库,动态库是在程序启动之后做的重定位,重定位分为两种 lazy bind: 主要用于模块外部的函数调用,...

  • iOS静态库开发制作

    库的种类 开源库 闭源库 闭源库分类 动态库链接时不复制,程序运行时由系统动态加载到内存中,供程序调用。系统只加载...

  • 应用程序加载

    程序加载流程: 动态链接器Dyld加载流程:1、环境变量的配置。2、共享缓存。3、主程序初始化。4、 加入动态库。...

  • chap 7

    1. 静态链接;加载时共享库的动态链接;运行时共享库的动态链接。 2. 预编译 编译 汇编 链接 加载...

  • iOS-静态库&动态库-Embed&Sign

    1、静态库&动态库 1.1 库介绍 程序的run流程:编译->链接->生成可执行文件->运行(加载可执行文件&动态...

  • _dl_runtime_resolve

    简介 在Linux中如果程序想要调用其它动态链接库的函数,必须要在程序加载的时候动态链接;在一个程序运行过程中,可...

  • 动态链接库加载的具体流程

    动态链接库加载的具体流程 动态链接库的加载步骤具体分为5步: load dylibs image 读取库镜像文件 ...

  • iOS逆向-代码注入(IV)

    framework注入 dyld dyld (动态库加载器),负责加载程序和程序所有依赖的动态库。内核读取 Mac...

网友评论

    本文标题:程序的加载与链接(六) 动态库 lazy bind

    本文链接:https://www.haomeiwen.com/subject/srirbctx.html