如何为DLL函数编写(通用)自替换存根函数?

问题描述 投票:1回答:3

我有一些功能,比如我从DLL获取的int foo(int x)(使用dlsym())。所以,目前我的代码看起来像这样:

void foo(int x) {
    void (*foo)(int x);
    foo = dlsym(dll_handle, "foo");
    int y = foo(x);
    printf("y is %d", y);
}

我想要的是(像这样的代码):

void bar(int x) {
    int y = foo(x);
    printf("y is %d", y);
}

所以foo()是一个调用dll函数的存根(但不必每次都搜索DLL)。

  1. 实现单一功能的最佳方法是什么?
  2. 对于许多函数的情况,我如何避免编写一堆复制粘贴存根?考虑到签名,宏解决方案可能很棘手。也许基于C ++ 11的variadic-arg基于模板的东西?

我在下面的答案中有一个解决方案的基本想法,但我不太确定,我想在这里采用“最佳实践”方法。

c stub idioms dlopen idiomatic
3个回答
1
投票

你已经在问题中回答了自己。一个小的改进可能是检查dll的“更新”,如果有的话。

int foo(int x) {
     static void (*dll_foo)(int x) = NULL;
     static void *foo_dll_handle = NULL;
     if (dll_foo == NULL || foo_dll_handle != dll_handle) {
          dll_foo = dlsym(dll_handle, "foo");
          foo_dll_handle = dll_handle;
     }
     return dll_foo(x);
}

1
投票

对于许多函数的情况,我如何避免编写一堆复制粘贴存根?

它已经很长时间但是为了完整性,您可以使用Implib.so自动生成这样的包装器:

$ implib-gen.py mylib.so

这将生成两个文件,mylib.so.tramp.S和mylib.so.init.c。汇编文件包含库函数的包装器(可选择dlopen库并使用dlsym来定位正确的实现):

// Wrapper for bar symbol
  .globl bar
bar:
  .cfi_startproc
  // Check if library function address is resolved
  cmp $0, _libtest_so_tramp_table+0(%rip)
  je 2f
1:
  // Fast path
  jmp *_libtest_so_tramp_table+0
2:
  // Slow path
  pushq $0
  .cfi_adjust_cfa_offset 8
  call save_regs_and_resolve
  addq $8, %rsp
  .cfi_adjust_cfa_offset -8
  jmp 1b
  .cfi_endproc

生成的C代码处理dlopendlsym部分:

void _libtest_so_tramp_resolve(int i) {
  assert(i < sizeof(sym_names) / sizeof(sym_names[0]) - 1);
  if(!lib_handle) {
    lib_handle = dlopen("libtest.so", RTLD_LAZY | RTLD_GLOBAL);
  }
  CHECK(lib_handle, "failed to load library 'libtest.so': %s", dlerror());

  // Can be sped up by manually parsing library symtab...
  _libtest_so_tramp_table[i] = dlsym(lib_handle, sym_names[i]);
  CHECK(_libtest_so_tramp_table[i], "failed to resolve symbol '%s' in library 'libtest.so'", sym_names[i]);
}

有关更多信息,请查看projects Github page


0
投票

对于单个函数的情况,我认为这样的事情应该是正确的:

int foo(int x) {
     static void (*dll_foo)(int x) = NULL;
     if (dll_foo == NULL) {
          dll_foo = dlsym(dll_handle, "foo");
     }
     return dll_foo(x);
}
© www.soinside.com 2019 - 2024. All rights reserved.