第十一节 动态符号对象(DSO, Dynamic Symbol Object)
第十一节 动态符号对象(DSO, Dynamic Symbol Object)
由 admin 于 周四, 2007-07-26 17:30 提交。You might know so(shared object) or dll(dynamic link library). Essentially, DSO is dependent on so/dll. Now, we call so/dll 'dynamic library' to distinguish from dso.
你可能知道so (共享对象shared object)或者dll(动态链接库)。本质上,DSO是依赖于so/dll。现在我们调用一个so/dll来区分dso。
To understand dso, we should know how link and load work. In general, when we use dynamic libraries, we link them with your program at a build time. ld(1) takes care of it on Unix. ld(1) is known as link editor. Since ld(1) is usually called by gcc(1) implicitly, you wouldn't be aware of ld(1). We sometimes happen to see link error messages at a compile time. It means ld(1) can't resolve the symbols that you're using in your program. At a runtime, ld.so(8) loads the dynamic libraries. If it failed, you would see load error messages. A summary is that link is done at a compile(build) time, and load is done at a runtime. If you want to know more, please read manuals of ld(1) and ld.so(8).
为了理解DSO,我们应该知道链接和装载是怎样工作的。大体上来讲当我们使用一个动态库(dynamic libraries)的时候,我们的链接你的程序中,在Unix中ld负责这件事情,ld是一个链接的编辑器。ld通常被gcc隐含调用,你不必关心ld做了什么,有时候我们会在编译时出现链接错误提示,这可能是因为ld不能解析你程序中所使用的符号。在运行的时候,ld.so加载动态库,如果失败你会看到加载是错误的提示信息。结论就是链接发生在编译的时候,而加载出现在运行的时候。如果你想了解更多内容,请阅读ld和ld.so的手册
By dso, both link and load are done at a runtime. Why do we use such a mechanism? The reason is that we can make plugin architecture. All we have to do during a build time is to define the interfaces(symbol names and how we call them) of loadable modules. The program loads the modules at a runtime and use them through the interfaces. Loadable modules can be developed by independent programmers. This can make the system very flexible and extensible.
DSO链接和加载都发生在运行的时候,为什么我们要用这样的一种机制?理由就是我们构建一个插件事架构的程序。我们需要作的只是在构建程序时候定义被加载模块的接口。程序在运行时候通过这些接口加载这些模块。可加载的模块可以由一些独立的程序员完成。这样能使真哥哥系统更加灵活和更利于扩展。
Let's take a look at dso-sample.c. You can find two strings "libm.so" and "pow" in dso-sample.c. In fact, pow(3) is a trivial function and it doesn't worth calling as dso, but it is just an example code.
让我们看一下dso-sample.c示例代码,我们能够在dso-sample.c文件中找到另个字符串“libm.so”和“pow”。 事实上pow是一个很小的函数,并不需要使用DSO这种方式,但这仅仅是一示例代码。
At first, we call apr_dso_load() and to pass the library file name, "libm.so".
首先,我们需要调用apr_dso_load()并且传入库文件名“libm.so”。
/* excerpted from dso-sample.c, but I omitted error checks */
const char fname[] = "libm.so";
apr_dso_handle_t *dso_h;
apr_dso_load(&dso_h, fname, mp);
As you can imagine, if you want your program to have plugins, you need a way to indicate the plugin file names. We can find such a system, apache modules. Their module names are specified in "httpd.conf" file.
你可以想像如果你在你的程序中使用插件机制,你需要一种获取插件文件名的方式。我们发现Apache的模块,他们的模块名称都是通过“httpd.conf”文件指定的。
apr_dso_load() happens to fail. The cause is usually that it can't find the dynamic library file. The search path for dynamic library files at a runtime is dependent on OS. On GNU/Linux, it depends on LD_LIBRARY_PATH environment variable. On MS-Windows, it depends on PATH environment variable. After apr_dso_load() returns successfully, we can call apr_dso_sym(). The prototype declaration is as follows:
apr_dso_load()发生失败的原因通常是因为找不到动态读文件。运行时动态库文件的搜索路径依赖于操作系统。在GNU/Linux中,他依赖于LD_LIBRARY_PATH环境变量。在MS-Windows中,它依赖于PATH环境变量。在apr_dso_load()返回成功之后,我们需要调用apr_dso_sym(),下面是他的原型定义:
/* excerpted from apr_dso.h */
APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, apr_dso_handle_t *handle, const char *symname);
By apr_dso_sym(), we can get a symbol object by a symbol name. The first argument is result argument. The second argument is dso handle, which we can get by apr_dso_open() above. The third argument is symbol name.
通过apr_dso_sym()我们可以通过符号的名字得到符号对象,第一个参数是结构参数(result argument),第二个参数是DSO的处理句柄(handle),我们可以使用apr_dso_open()获得DSO的句柄,第三个参数是符号名称。
The following code is excerpted from dso-sample.c. The symbol name is "pow" and we get a function pointer as a symbol object. Since we know pow(3)'s interface, we can have typedef'd pow_fn_t.
下面是从dso-sample.c示例中获得代码,符号名称是“pow”并且我们得到了这个符号对象函数指针,因为我们知道pow()的接口,我们定义一个pow_fn_t类型。
/* excerpted from dso-sample.c, but I omitted error checks */
typedef double (*pow_fn_t)(double x, double y);
pow_fn_t pow_fn;
/* seek pow(3) function from libm.so */
apr_dso_sym((apr_dso_handle_sym_t*)&pow_fn, dso_h, "pow");
/* call pow(3) */
printf("%d ^ %d = %f\n", 2, 2, pow_fn(2, 2));
If your program has plugins, you have to define the symbol names and their interfaces. Then, plugin developers must follow them.
如果你的程序需要插件这样的方式,你需要定义符号名称和他们的接口,然后插件的开发人员必须服从这些约定进行开发。
Finally, we call apr_dso_unload() to release the loadable module. It could reduce memory consumption.
最后,我们需要调用apr_dso_unload()释放已加载的模块,这样能够降低内存的开销。
疑问