• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 动态共享对象(DSO)支持

    使用摘要

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

    1. 例如,将分布式 Apache httpd模块构建并安装mod_foo.c到其自己的DSO中mod_foo.so

      $ ./configure --prefix=/path/to/install --enable-foo
      $ make install
      
    2. 在启用所有模块的情况下配置Apache HTTP Server。服务器启动期间将仅加载基本集。您可以通过激活或停用中的LoadModule指令来更改已加载模块的集合httpd.conf

      $ ./configure --enable-mods-shared=all
      $ make install
      
    3. 一些模块仅对开发人员有用,无法构建。使用模块时设置全部。要构建包括开发人员模块在内的所有可用模块,请使用realall。另外,LoadModule可以通过configure选项激活所有内置模块的指令--enable-load-all-modules

      $ ./configure --enable-mods-shared=reallyall --enable-load-all-modules
      $ make install
      
    4. 例如,使用以下命令在Apache httpd源代码树之外构建第三方 Apache httpd模块mod_foo.c并将其安装到其自己的DSO中:mod_foo.soapxs
      $ cd /path/to/3rdparty
      $ apxs -cia mod_foo.c
      

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

    有关更多详细信息,请参见apxs文档。

    背景

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

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

    在第一种方式中,DSO通常称为共享库DSO库,并命名为libfoo.solibfoo.so.1.2。它们驻留在系统目录中(通常为/usr/lib),并且通过指定-lfoolinker命令在构建时建立到可执行程序的链接。此硬编码库引用到可执行程序文件,以便在起动时Unix加载器能够定位libfoo.so/usr/lib,在路径经由像接头选项硬编码-R或通过环境变量配置的路径LD_LIBRARY_PATH。然后,它解析DSO中可用的可执行程序中的任何符号(但尚未解析)。

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

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

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

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

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

    的优点和缺点

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

    • 服务器软件包在运行时更加灵活,因为可以在运行时通过LoadModulehttpd.conf配置指令而不是configure在构建时通过选项来组装服务器进程。例如,通过这种方式,仅安装一个Apache httpd 即可运行不同的服务器实例(标准和SSL版本,简约和动态版本[mod_perl,mod_php])。
    • 即使在安装后,也可以使用第三方模块轻松扩展服务器软件包。对于供应商软件包维护者来说,这是一个很大的好处,他们可以创建一个Apache httpd核心软件包以及其他包含PHP,mod_perl,mod_security 扩展名的软件包
    • 简化Apache httpd模块的原型制作,因为使用DSO /apxs对,您可以在Apache httpd源代码树之外工作,并且只需要一个apxs -i命令后跟一个apachectl restart即可将当前开发的模块的新版本引入正在运行的Apache HTTP Server。

    DSO具有以下缺点:

    • 由于符号解析现在需要Unix加载程序要做的工作,因此服务器在启动时会慢大约20%。
    • 在某些平台上,服务器在执行时的速度要慢大约5%,因为位置无关代码(PIC)有时需要复杂的汇编技巧来进行相对寻址,这不一定要与绝对寻址一样快。
    • 由于无法ld -lfoo在所有平台上将DSO模块与其他基于DSO的库()链接(例如,基于a.out的平台通常不提供此功能,而基于ELF的平台却不提供),因此无法将DSO机制用于所有类型的模块。换句话说,编译为DSO文件的模块只能使用Apache httpd核心,C库(libc)和Apache httpd核心使用的所有其他动态或静态库或libfoo.a包含以下内容的静态库档案()中的符号:位置无关代码。使用其他代码的唯一机会是确保httpd核心本身已经包含对其的引用,或者自己通过加载代码dlopen()