动态共享对象(DSO)支持

Apache HTTP Server 是一个模块化程序,Management 员可以在其中选择一组模块来选择要包含在服务器中的功能。模块将被编译为与主要httpd二进制文件分开存在的动态共享对象(DSO)。 DSO 模块可以在构建服务器时进行编译,也可以在以后使用 Apache 扩展工具(apxs)进行编译和添加。

或者,可以在构建服务器时将模块静态编译为httpd二进制文件。

本文档介绍了如何使用 DSO 模块以及其使用背后的理论。

Implementation

Related Modules Related Directives
mod_so LoadModule

DSO 对加载单个 Apache httpd 模块的支持基于名为mod_so的模块,该模块必须静态编译到 Apache httpd 内核中。它是core之外唯一无法放入 DSO 的模块。实际上,所有其他分布式 Apache httpd 模块都将放入 DSO。将模块编译成名为mod_foo.so的 DSO 之后,可以在httpd.conf文件中使用mod_soLoadModule指令在服务器启动或重新启动时加载此模块。

install documentation中所述,可以通过configure--enable-mods-static选项禁用针对单个模块的 DSO 构建。

为了简化针对 Apache httpd 模块(尤其是第三方模块)的 DSO 文件的创建,提供了名为apxs(APache eXtenSion)的支持程序。它可以用于在 Apache httpd 源代码树之外构建基于 DSO 的模块。这个想法很简单:安装 Apache HTTP Server 时,configuremake install过程将安装 Apache httpd C 头文件,并将用于构建 DSO 文件的平台相关的编译器和链接器标志放入apxs程序中。这样,用户可以使用apxs来编译他的 Apache httpd 模块源,而无需使用 Apache httpd 分发源树,而不必摆弄 DSO 支持的依赖于平台的编译器和链接器标志。

Usage Summary

为了让您大致了解 Apache HTTP Server 2.x 的 DSO 功能,以下是一个简短的摘要:

$ ./configure --prefix=/path/to/install --enable-foo $ make install

$ ./configure --enable-mods-shared=all $ make install

$ ./configure --enable-mods-shared=reallyall --enable-load-all-modules $ make install

$ cd /path/to/3rdparty $ apxs -cia mod_foo.c

在所有情况下,一旦编译了共享模块,就必须在httpd.conf中使用LoadModule指令来告诉 Apache httpd 激活该模块。

有关更多详细信息,请参见apxs documentation

Background

在现代 Unix 派生工具中,存在一种称为“动态共享对象”(DSO)的动态链接/加载的机制,该机制提供了一种构建一段特殊格式的程序代码的方法,以便在运行时将其加载到程序的地址空间中。可执行程序。

这种加载通常可以通过两种方式完成:启动可执行程序时由称为ld.so的系统程序自动完成,或者通过编程系统接口通过执行系统调用dlopen()/dlsym()到 Unix 加载器,从正在执行的程序中手动进行加载。

在第一种方式中,DSO 通常称为共享库或* DSO 库*,并命名为libfoo.solibfoo.so.1.2。它们位于系统目录(通常为/usr/lib)中,并且通过在链接器命令中指定-lfoo来在构建时构建到可执行程序的链接。该硬代码库引用了可执行程序文件,因此在启动时,Unix 加载程序能够在/usr/lib中,通过链接器选项(例如-R)进行硬编码的路径中或通过环境变量LD_LIBRARY_PATH配置的路径中找到libfoo.so。然后,它解析 DSO 中可用的可执行程序中的任何(尚未解析的)符号。

DSO 通常不引用可执行程序中的符号(因为它是通用代码的可重用库),因此无需进行进一步的解析。可执行程序不需要自己做任何事情即可使用 DSO 中的符号,因为完全的解析是由 Unix 加载器完成的。 (实际上,调用ld.so的代码是运行时启动代码的一部分,该代码链接到已绑定为非静态的每个可执行程序中)。动态加载公共库代码的优势非常明显:库代码只需要存储一次(在libc.so之类的系统库中),从而可以为每个程序节省磁盘空间。

在第二种方式中,DSO 通常称为共享对象或* DSO 文件*,并且可以使用任意 extensions 进行命名(尽管规范名称为foo.so)。这些文件通常位于特定于程序的目录中,并且没有自动构建指向使用它们的可执行程序的链接。相反,可执行程序在运行时通过dlopen()手动将 DSO 加载到其地址空间中。此时,尚未完成来自 DSO 的可执行程序符号解析。但是,相反,Unix 加载器会从可执行程序及其已加载的 DSO 库导出的符号集中自动解析 DSO 中的任何符号(尚未解析)(尤其是来自普遍存在的libc.so的所有符号)。这样,DSO 就可以像首先将其静态链接一样,获取可执行程序符号集的知识。

最后,为了利用 DSO 的 API,可执行程序必须通过dlsym()解析 DSO 中的特定符号,以供以后在调度表* etc. *中使用。换句话说:可执行程序必须手动解析其需要的每个符号使用它。这种机制的优势在于,在相关程序需要可选程序部件之前,不需要加载它们(因此不会浪费内存)。必要时,可以动态加载这些程序部分以扩展基本程序的功能。

尽管这种 DSO 机制听起来很简单,但是这里至少有一个困难的步骤:使用 DSO 扩展程序时,从可执行程序中解析 DSO 的符号(第二种方法)。为什么?因为从可执行程序的符号集中“反向解析” DSO 符号违反了库的设计(库不了解其所使用的程序),并且在所有平台上都不可用,也不是标准化的。实际上,可执行程序的全局符号通常不会重新导出,因此无法在 DSO 中使用。找到一种方法来强制链接器导出所有全局符号是在运行时使用 DSO 扩展程序时必须解决的主要问题。

共享库方法是典型的方法,因为它是 DSO 机制的设计目的,因此几乎用于 os 提供的所有类型的库。

优缺点

上述基于 DSO 的功能具有以下优点:

DSO 具有以下缺点:

首页