2014-01-08 49 views
1

我有一些函数,比如int foo(int x),我从一个DLL中获得(使用dlsym())。所以,目前我的代码看起来是这样的:如何为DLL函数编写(通用)自我替换存根函数?

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的可变参数模板为基础的东西?

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

+0

这肯定会起作用,但当不再需要时,它不会用'dlclose(3)'卸载共享库。这可能是好的,但是如果你想能够卸载库,你需要一个deinitialization函数来调用dlclose()并将dll_foo变量设置为NULL。 –

回答

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); 
} 
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); 
} 
1

对于许多功能的情况下,我怎么会避免写一堆 复制粘贴存根?

这是一个很长一段时间,但为了完整起见,你可以使用Implib.so自动生成这样的包装:

$ gen-implib.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

1.您可以举一些生成的存根的例子吗? 2.什么是.S文件? – einpoklum

+0

@einpoklum当然,附上。 .S文件将生成最快的存根功能(它们与普通PLT调用一样快)。 – yugr

+0

在C示例中,lib_handle的定义在哪里?这是全球性的吗?此外,C示例似乎总是采用“慢路径”。在汇编文件快速路径中,“+0”是做什么的? – einpoklum