[转] (6) OpenSSL 之动态模块加载

发布时间:2010-4-4 19:58
分类名称:OpenSSL


动态库加载
动态库加载函数能让用户在程序中加载所需要的模块,各个平台下的加载函数是不一样的。动态加载函数一般有如下功能:
1) 加载动态库
比如windows下的函数LoadLibraryA;linux下的函数dlopen。这些函数一般需要动态库的名字作为参数。

2) 获取函数地址
比如windows下的函数GetProcAddress已及linux下的函数dlsym。这些函数一般需要函数名作为参数,返回函数地址。

3) 卸载动态库
比如windows下的函数FreeLibrary和linux下的函数dlclose。

DSO概述
DSO可以让用户动态加载动态库来进行函数调用。各个平台下加载动态库的函数是不一样的,openssl的DSO对各个平台台下的动态库加载函数进行了封装,增加了源码的可移植性。Openssl的DSO功能主要用于动态加载压缩函数(ssl协议)和engine(硬件加速引擎)。Openssl的DSO功能除了封装基本的功能外还有其他辅助函数,主要用于解决不同系统下路径不同的表示方式以及动态库全名不一样的问题。比如windows系统下路径可以用“\\”和“/”表示,而linux下只能使用“/”;windows下动态库的后缀为.dll而linux下动态库名字一般为libxxx.so。

数据结构
dso数据结定义在crypto/dso/dso.h中,如下所示:
struct dso_st
{
DSO_METHOD *meth;
STACK *meth_data;
int references;
int flags;
CRYPTO_EX_DATA ex_data;
DSO_NAME_CONVERTER_FUNC name_converter;
DSO_MERGER_FUNC merger;
char *filename;
char *loaded_filename;
};
meth:指出了操作系统相关的动态库操作函数。
meth_data:堆栈中存放了加载动态库后的句柄。
reference:引用计数,DSO_new的时候置1,DSO_up_ref时加1,DSO_free时减1。
当调用DSO_free时,只有当前的references为1时才真正释放meth_data中存放的句柄。
flag:与加载动态库时加载的文件名以及加载方式有关,用于DSO_ctrl函数。
DSO_convert_filename:当加载动态库时会调用DSO_convert_filename函数来确定所加载的文件。而DSO_convert_filename函数会调用各个系统自己的convert函数来获取这个文件名。
对于flag有三种种操作命令:设置、读取和或的关系,对应定义如下:
#define DSO_CTRL_GET_FLAGS 1
#define DSO_CTRL_SET_FLAGS 2
#define DSO_CTRL_OR_FLAGS 3
而flag可以设置的值有如下定义:
#define DSO_FLAG_NO_NAME_TRANSLATION 0x01
#define DSO_FLAG_NAME_TRANSLATION_EXT_ONLY 0x02
#define DSO_FLAG_UPCASE_SYMBOL 0x10
#define DSO_FLAG_GLOBAL_SYMBOLS 0x20
意义说明如下:
DSO_FLAG_NO_NAME_TRANSLATION
加载的文件名与指定的文件名一致,不加后缀.dll(windows)或.so(linux或unix)。
DSO_FLAG_NAME_TRANSLATION_EXT_ONLY
加载的文件名会加上lib串,比如用户加载eay32,真正加载时会加载libeay32(适用于linux或unix)。
DSO_FLAG_UPCASE_SYMBOL
适用于OpenVMS。
DSO_FLAG_GLOBAL_SYMBOLS
适用于unix,当在unix下调用加载函数dlopen时,参数会被或上RTLD_GLOBAL。
ex_data:扩展数据,没有使用。
name_converter::指明了具体系统需要调用的名字计算函数。

loaded_filename:指明了加载动态库的全名。


编程示例
示例1:
#include <openssl/dso.h>
#include <openssl/bio.h>
int main()
{
DSO *d;
void (*f1)();
void (*f2)();
BIO *(*BIO_newx)(BIO_METHOD *a);
BIO *(*BIO_freex)(BIO_METHOD *a);
BIO *test;

d=DSO_new();
d=DSO_load(d,"libeay32",NULL,0);
f1=DSO_bind_func(d,"BIO_new");
f2=DSO_bind_var(d,"BIO_free");
BIO_newx=(BIO *(*)(BIO_METHOD *))f1;
BIO_freex=(BIO *(*)(BIO_METHOD *))f2;
test=BIO_newx(BIO_s_file());
BIO_set_fp(test,stdout,BIO_NOCLOSE);
BIO_puts(test,"abd\n\n");
BIO_freex(test);
DSO_free(d);
return 0;
}
本例动态加载libeay32动态库,获取BIO_new和BIO_free的地址并调用。
示例2:
#include <openssl/dso.h>
#include <openssl/bio.h>
int main()
{
DSO *d;
void (*f)();
BIO *(*BIO_newx)(BIO_METHOD *a);
BIO *test;
char *load_name;
const char *loaded_name;
int flags;

d=DSO_new();
#if 0
DSO_set_name_converter
DSO_ctrl(d,DSO_CTRL_SET_FLAGS,DSO_FLAG_NO_NAME_TRANSLATION,NULL);
DSO_ctrl(d,DSO_CTRL_SET_FLAGS,DSO_FLAG_NAME_TRANSLATION_EXT_ONLY,NULL);
DSO_ctrl(d,DSO_CTRL_SET_FLAGS,DSO_FLAG_GLOBAL_SYMBOLS,NULL);
/* 最好写成libeay32而不是libeay32.dll, 除非前面调用了DSO_ctrl(d,DSO_CTRL_SET_FLAGS,DSO_FLAG_NO_NAME_TRANSLATION,NULL)否则它会加载libeay32.dll.dll
*/
load_name=DSO_merge(d,"libeay32","D:\\zcp\\OpenSSL\\openssl-0.9.8b\\out32dll\\Debug");
#endif
d=DSO_load(d,"libeay32",NULL,0);

{
printf("err");
return -1;
}
loaded_name=DSO_get_loaded_filename(d);

{
printf("loaded file is %s\n",loaded_name);

}
flags=DSO_flags(d);
printf("current falgs is %d\n",flags);
DSO_up_ref(d);
f=(void (*)())DSO_bind_var(d,"BIO_new");
BIO_newx=(BIO *(*)(BIO_METHOD *))f;
test=BIO_newx(BIO_s_file());
BIO_set_fp(test,stdout,BIO_NOCLOSE);
BIO_puts(test,"abd\n\n");
BIO_free(test);
DSO_free(d);
printf("handle in dso number is : %d\n",d->meth_data->num);
DSO_free(d);
printf("handle in dso number is : %d\n",d->meth_data->num);
return 0;
}
本例主要演示了DSO的控制函数。