dlopen 和 dlsym 动态调用函数

dlopen 和 dlsym 动态调用函数

 iOS/MacOSX/移动安全  exchen  2年前 (2018-08-20)  2997浏览  0评论

Linux/unix 提供了使用 dlopen 和 dlsym 方法动态加载库和调用函数,这套方法在 macOS 和 iOS 上也支持。

dlopen 打开一个库,获取句柄。
dlsym 在打开的库中查找符号的值。
dlclose 关闭句柄。
dlerror 返回一个描述最后一次调用dlopen、dlsym,或 dlclose 的错误信息的字符串。

动态调用 printf 函数,编写测试代码如下:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

#import <dlfcn.h>

 

typedef int (*printf_func_pointer) (const char * __restrict, ...);

 

void dynamic_call_function(){

    

    //动态库路径

    char *dylib_path = "/usr/lib/libSystem.dylib";

    

    //打开动态库

    void *handle = dlopen(dylib_path, RTLD_GLOBAL | RTLD_NOW);

    if (handle == NULL) {

        //打开动态库出错

        fprintf(stderr, "%s\n", dlerror());

    } else {

        

        //获取 printf 地址

        printf_func_pointer printf_func = dlsym(handle, "printf");

        

        //地址获取成功则调用

        if (printf_func) {

            int num = 100;

            printf_func("Hello exchen.net %d\n", num);

            printf_func("printf function address 0x%lx\n", printf_func);

        }

        

        dlclose(handle); //关闭句柄

    }

}

 

int main(int argc, char * argv[]) {

    @autoreleasepool {

        

        dynamic_call_function();

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

    }

}

在手机上运行的输出结果如下:

 

1

2

Hello exchen.net 100

printf function address 0x189f0da78

 

转载请注明:exchen's blog » [iOS Hacker] dlopen 和 dlsym 动态调用函数

 

补充dlsym():

获取新符号

进程可以使用 dlsym(3C) 获取特定符号的地址。此函数采用句柄符号名称,并将符号地址返回给调用方。该句柄通过以下方式指示符号搜索:

  • 可通过指定目标文件的 dlopen(3C) 返回句柄。该句柄允许从指定目标文件及定义其依赖项树的目标文件获取符号。使用模式 RTLD_FIRST 返回的句柄仅允许从指定目标文件获取符号。

  • 可通过其值为 0 的路径名的 dlopen(3C) 返回句柄。该句柄允许从关联链接映射的启动目标文件及定义其依赖项树的目标文件获取符号。通常,启动目标文件为动态可执行文件。对于关联链接映射,该句柄还允许从通过 dlopen(3C) 获取且模式为 RTLD_GLOBAL 的任何目标文件获取符号。使用模式 RTLD_FIRST 返回的句柄仅允许从关联链接映射的启动目标文件获取符号。

  • 特殊句柄 RTLD_DEFAULT 和 RTLD_PROBE 允许从关联链接映射的启动目标文件及定义其依赖项树的目标文件获取符号。此句柄还允许从通过 dlopen(3C) 获取且与调用方同属一组的任何目标文件获取符号。 使用 RTLD_DEFAULT 或 RTLD_PROBE 时采用在解析调用目标文件中的符号重定位时所用的同一模型。

  • 特殊句柄 RTLD_NEXT 允许从调用方链接映射列表中的下一个关联目标文件获取符号。

在以下可能很常见的示例中,应用程序首先会将其他目标文件添加到其地址空间。然后,应用程序会使用 dlsym(3C) 来查找函数或数据符号。接下来,应用程序将使用这些符号来调用这些新目标文件中提供的服务。文件 main.c 包含以下代码:

 
#include    <stdio.h>

#include    <dlfcn.h>

 

main()

{

        void *  handle;

        int *   dptr, (* fptr)();

 

        if ((handle = dlopen("foo.so.1", RTLD_LAZY)) == NULL) {

                (void) printf("dlopen: %s\n", dlerror());

                exit (1);

        }

 

        if (((fptr = (int (*)())dlsym(handle, "foo")) == NULL) ||

            ((dptr = (int *)dlsym(handle, "bar")) == NULL)) {

                (void) printf("dlsym: %s\n", dlerror());

                exit (1);

        }

 

        return ((*fptr)(*dptr));

}

首先会在文件 foo.so.1 中搜索符号 foo 和 bar,然后在与此文件关联的所有依赖项中搜索。接下来,在 return() 语句中使用单个参数 bar 调用函数 foo。

使用前面的文件 main.c 生成的应用程序 prog 包含下列依赖项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值