(转) apache dso 与 linux so 动态库加载方法的差别

DSO的产生当然离不开操作系统的支持。目前不管是UNIX还是Linux,大多都提供了对动态共享对象或动态链接库进行加载和卸载的机制。加载的方法通常有两种:其一是在可执行文件启动时由系统程序ld.so自动加载;其二是在执行程序过程中手工通过Unix提供的动态链接库加载接口进行加载。

1.Linux下的DSO

     Linux下的DSO操作函数主要包括以下几个:

  •     void *dlopen(const char *pathname, int mode);  

           该函数用来加载动态库,其中pathname是需要加载的库的路径名称,mode则是加载的方式。可以为三个值:RTLD_LAZY表示未定义的符号是来自动态链接库的代码;RTLD_NOW表示要在dlopen返回前确定所有未定义的符号,如不能完成,则执行失败;而RTLD_GLOBAL则表示动态链接库中定义的外部符号可以被随后加载的库使用。如果函数执行成功,将返回动态链接库中的一个句柄。一旦对动态库进行了加载,就可以通过dlsym函数获取库中的函数调用及各种定义的符号等。

  •     void *dlsym(void *handle, char *symbol);

           其中,handle是加载的动态链接库的句柄,它通常是dlopen函数的操作结果;symbol是要得到的动态链接库中的符号名称。如果找不到symbol,函数将返回NULL。

           在所有的操作结束后,Linux可以通过dlclose将dlopen先前打开的共享对象从当前进程断开,但只有当动态链接库的使用计数为0时,该共享对象才会真正被卸载。

  •     int dlclose(void *handle);

           一旦使用dlclose关闭了对象,dlsym就再也不能使用它的符号了。

       简单演示dlopen、dlsym、dlclose三部曲的使用:

 
  1. void *handle, *handle2;

  2. handle = dlopen("libdisplay.so", RTLD_LAZY);

  3. if (handle != NULL) {

  4. handle2 = dlsym(handle, "draw");

  5. if (handle2 != NULL) {

  6. ...... /* use the function */

  7. }

  8. /* When finished, unload the shared library */

  9. dlclose(handle);

  10. }

2.APR DSO封装

    Apache中提供了统一的DSO操作接口,以便在不同的操作系统平台上执行相同的操作,这四个接口分别为:

     (1) APR_DECLARE(apr_status_t)apr_dso_load(apr_dso_handle_t **res_handle, const char *path, apr_pool_t *ctx);

          apr_dso_load函数实现对so文件的动态加载。path是so文件的绝对路径,ctx则是其使用的内存池,该函数用来载入DSO动态共享库。res_handle_Location用来存储新的DSO的处理句柄,path则是DSO库的路径位置。

         apr_dso_load的实现分为7种平台:AIX、beos、netware、OS2、OS390、Unix及Win32.

         apr_dso_load内部首先调用dlopen对模块进行加载,然后返回加载后的句柄os_handle,同时将句柄保存在apr_dso_handle_t类型变量res_handle的handle中。res_handle需要的所有资源来自内存池ctx.最后调用apr_pool_cleanup_register函数注册内存池ctx的清除函数dso_cleanup。下面是apr_dso_load加载的示例代码:

 
  1. const char fname[] = "libm.so";

  2. apr_dso_handle_t *dso_h;

  3. apr_dso_load(&dso_h, fname, pool);

           apr_dso_load()失败的原因通常是找不到动态读文件。运行时动态库文件的搜索路径依赖于操作系统。在GNU/Linux中,它依赖于LD_LIBRARY_PATH环境变量。在MS-Windows中,它依赖于PATH环境变量。

    (2) APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle);

         apr_dso_unload用以完成对指定so文件的卸载,handle是apr_dso_load返回的加载句柄。apr_dso_unload的实现则更简单,它只是调用了apr_pool_cleanup_run函数清除分配的内存池,同时调用dso_cleanup函数进行模块卸载。

    (3) APR_DECLARE(apr_status_t)apr_dso_sym(apr_dso_handle_sym_t *ressym,

                                                                                 apr_dso_handle_t *handle,

                                                                                 const char *symname);

         在apr_dso_load()返回成功之后,我们须调用apr_dso_sym()。apr_dso_sym()可以通过符号的名字得到符号对象,第一个参数是结构参数,第二个参数是DSO的处理句柄(handle),我们可以使用apr_dso_open()获得DSO的句柄,第三个参数是符号名称。

         下面是apr_dso_sym的调用代码,它用于从dso中获取符号名称是"pow"的函数指针,因为我们知道pow()的接口,定义一个pow_fn_t类型:

 
  1. typedef double(*pow_fn_t)(double x, double y);

  2. pow_fn_t pow_fn;

  3. apr_dso_sym((apr_dso_handle_sym_t *)&pow_fn, dso_h, "pow");

  4. printf("%d ^ %d = %f\n", 2, 2, pow_fn(2,2));

     (4) APR_DECLARE(const char *)apr_dso_error(apr_dso_handle_t *dso, char *buf, apr_size_t bufsize);

你可能感兴趣的:(Linux,编程)