nonocast / me

记录和分享技术的博客
http://nonocast.cn
MIT License
20 stars 0 forks source link

学习 C++ (Part 9: dylib 运行时加载) #239

Open nonocast opened 2 years ago

nonocast commented 2 years ago

使用一个dylib通常有2个方式,多数会采用编译时绑定,在做plugin的时候也会用到运行时链接。

在没有debug信息的时候,我们只能通过nm从dylib或so中获取symbols, 但无法获取完整的函数签名,所以如果在编译时就需要有header配合,在运行时就需要有对应的函数签名。

➜  file libcalc.dylib 
libcalc.dylib: Mach-O 64-bit dynamically linked shared library arm64
➜  size libcalc.dylib 
   text    data     bss     dec     hex filename
    104       0       0     104      68 libcalc.dylib

➜  gobjdump -x libcalc.dylib 

libcalc.dylib:     file format mach-o-arm64
libcalc.dylib
architecture: aarch64, flags 0x00000050:
HAS_SYMS, DYNAMIC
start address 0x0000000000000000
 MACH-O header:
   magic:      0xfeedfacf
   cputype:    0x100000c (ARM64)
   cpusubtype: 0 (ARM64_ALL)
   filetype:   0x6
   ncmds:      0xe
   sizeocmds:  0x298
   flags:      0x100085
   version:    2

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000020  0000000000003f98  0000000000003f98  00003f98  2**2
                  CONTENTS, ALLOC, LOAD, CODE
  1 __TEXT.__unwind_info 00000048  0000000000003fb8  0000000000003fb8  00003fb8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
SYMBOL TABLE:
0000000000003f98 g       0f SECT   01 0000 [.text] _add

➜  nm libcalc.dylib 
0000000000003f98 T _add

然后我们就可以通过dlopen, dlsym, dlclose操作:

#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <stdio.h>

typedef int (*add_func_pointer)(int, int);

int main(int args, char *argv[]) {
  char *calc_dylib_path = "./libcalc.dylib";
  printf("%s\n", calc_dylib_path);
  void *module = dlopen(calc_dylib_path, RTLD_LAZY);
  if (module == NULL) {
    printf("open dylib failed. (code=%s)\n", dlerror());
  }

  add_func_pointer add_func = dlsym(module, "add");
  if (add_func) {
    int sum = add_func(2, 7);
    printf("2+7=%d\n", sum);
  }

  dlclose(module);
  return 0;
}

obs的整个plugin体系就是通过dlopen来实现的。

参考阅读