在获取函数地址时如何获得RTLD_LAZY行为?

我们有一个很大程度上依赖于使用dlopen()加载模块的系统。 我们的模块是自我描述的,带有一个符号,指向一些与加载模块相关的元数据(描述,加载顺序,加载标志等)。

我们首先将指定RTLD_LAZY标志的模块加载到dlopen()中,从元数据中获得我们需要的内容,然后稍后加载模块(在我们知道加载顺序应该是什么,它们应该如何加载等) 。

这一段时间工作得很好,但是最近我们发现,获取函数的地址需要在加载时parsing函数。 有什么办法可以解决这个问题?

我已经放了一个相当小的例子来说明问题。

 /* foo.h */ void foo(void); /* foo.c */ void foo(void) {} /* bar.c */ #include "foo.h" /* Calls foo normally */ void bar(void) { foo(); } /* bam.c */ #include "foo.h" static void (*f)(void); /* Takes the address of foo */ void bam(void) { f = foo; } /* rtld_lazy.c */ #include <dlfcn.h> #include <stdio.h> void check(const char *module) { void *mod = dlopen(module, RTLD_LAZY); if (mod) { printf("%s successfully loaded\n", module); dlclose(mod); } else { printf("%s failed to load: %s\n", module, dlerror()); } } int main() { check("./bar.so"); check("./bam.so"); check("./foo.so"); } 

有了以下输出:

 ./bar.so successfully loaded ./bam.so failed to load: ./bam.so: undefined symbol: foo ./foo.so successfully loaded 

您应该使用dlsym()来获取符号的地址。 参见POSIX:

http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html

我们提出了两种解决这个问题的方法,视情况而定。

第一个是在调用者的模块中,为这个函数写一个小的静态包装器。 静态包装将动态绑定到有问题的函数,并且可以毫无问题地取得该函数的地址。

 /* bam.c */ #include "foo.h" static void (*f)(void); static void foo_wrapper(void) { foo(); } /* Takes the address of foo */ void bam(void) { f = foo_wrapper; } 

如果你发现自己编写了很多这样的小包装,你可以把一个函数返回给你提供的模块。

 /* foo.h */ void foo(void); typedef void (*foo_ptr_type)(void); foo_ptr_type foo_ptr(void); /* foo.c */ void foo(void) {} foo_ptr_type foo_ptr(void) { return foo; } /* bam.c */ #include "foo.h" static void (*f)(void); /* Takes the address of foo */ void bam(void) { f = foo_ptr(); }