| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> |
| <HTML><HEAD> |
| <TITLE>Apache 1.3 Dynamic Shared Object (DSO) support</TITLE> |
| </HEAD> |
| |
| <!-- Background white, links blue (unvisited), navy (visited), red (active) --> |
| <BODY |
| BGCOLOR="#FFFFFF" |
| TEXT="#000000" |
| LINK="#0000FF" |
| VLINK="#000080" |
| ALINK="#FF0000" |
| > |
| <BLOCKQUOTE> |
| <!--#include virtual="header.html" --> |
| |
| <DIV ALIGN=CENTER> |
| |
| <H1> |
| Apache 1.3<BR> |
| Dynamic Shared Object (DSO)<BR> |
| Support |
| </H1> |
| |
| <ADDRESS>Originally written by<BR> |
| Ralf S. Engelschall <rse@apache.org>, April 1998</ADDRESS> |
| |
| </DIV> |
| |
| <H3>Background</H3> |
| |
| <P>On modern Unix derivatives there exists a nifty mechanism usually called |
| dynamic linking/loading of <EM>Dynamic Shared Objects</EM> (DSO) which |
| provides a way to build a piece of program code in a special format for |
| loading it at run-time into the address space of an executable program. |
| |
| <P>This loading can usually be done in two ways: Automatically by a system |
| program called <CODE>ld.so</CODE> when an executable program is started or |
| manually from within the executing program via a programmatic system interface |
| to the Unix loader through the system calls <CODE>dlopen()/dlsym()</CODE>. |
| |
| <P>In the first way the DSO's are usually called <EM>shared libraries</EM> or |
| <EM>DSO libraries</EM> and named <CODE>libfoo.so</CODE> or |
| <CODE>libfoo.so.1.2</CODE>. They reside in a system directory (usually |
| <CODE>/usr/lib</CODE>) and the link to the executable program is established |
| at build-time by specifying <CODE>-lfoo</CODE> to the linker command. This |
| hard-codes library references into the executable program file so that at |
| start-time the Unix loader is able to locate <CODE>libfoo.so</CODE> in |
| <CODE>/usr/lib</CODE>, in paths hard-coded via linker-options like |
| <CODE>-R</CODE> or in paths configured via the environment variable |
| <CODE>LD_LIBRARY_PATH</CODE>. It then resolves any (yet unresolved) symbols in |
| the executable program which are available in the DSO. |
| |
| <P>Symbols in the executable program are usually not referenced by the DSO |
| (because it's a reusable library of general code) and hence no further |
| resolving has to be done. The executable program has no need to do anything on |
| its own to use the symbols from the DSO because the complete resolving is done |
| by the Unix loader. (In fact, the code to invoke <CODE>ld.so</CODE> is part of |
| the run-time startup code which is linked into every executable program which |
| has been bound non-static). The advantage of dynamic loading of common library |
| code is obvious: the library code needs to be stored only once, in a system |
| library like <CODE>libc.so</CODE>, saving disk space for every program. |
| |
| <P>In the second way the DSO's are usually called <EM>shared objects</EM> or |
| <EM>DSO files</EM> and can be named with an arbitrary extension (although the |
| canonical name is <CODE>foo.so</CODE>). These files usually stay inside a |
| program-specific directory and there is no automatically established link to |
| the executable program where they are used. Instead the executable program |
| manually loads the DSO at run-time into its address space via |
| <CODE>dlopen()</CODE>. At this time no resolving of symbols from the DSO for |
| the executable program is done. But instead the Unix loader automatically |
| resolves any (yet unresolved) symbols in the DSO from the set of symbols |
| exported by the executable program and its already loaded DSO libraries |
| (especially all symbols from the ubiquitous <CODE>libc.so</CODE>). This way |
| the DSO gets knowledge of the executable program's symbol set as if it had |
| been statically linked with it in the first place. |
| |
| <P>Finally, to take advantage of the DSO's API the executable program has to |
| resolve particular symbols from the DSO via <CODE>dlsym()</CODE> for later use |
| inside dispatch tables <EM>etc.</EM> In other words: The executable program has to |
| manually resolve every symbol it needs to be able to use it. The advantage of |
| such a mechanism is that optional program parts need not be loaded (and thus |
| do not spend memory) until they are needed by the program in question. When |
| required, these program parts can be loaded dynamically to extend the base |
| program's functionality. |
| |
| <P>Although this DSO mechanism sounds straightforward there is at least one |
| difficult step here: The resolving of symbols from the executable program for |
| the DSO when using a DSO to extend a program (the second way). Why? Because |
| "reverse resolving" DSO symbols from the executable program's symbol set is |
| against the library design (where the library has no knowledge about the |
| programs it is used by) and is neither available under all platforms nor |
| standardized. In practice the executable program's global symbols are often |
| not re-exported and thus not available for use in a DSO. Finding a way to |
| force the linker to export all global symbols is the main problem one has to |
| solve when using DSO for extending a program at run-time. |
| |
| <H3>Practical Usage</H3> |
| |
| <P>The shared library approach is the typical one, because it is what the DSO |
| mechanism was designed for, hence it is used for nearly all types of libraries |
| the operating system provides. On the other hand using shared objects for |
| extending a program is not used by a lot of programs. |
| |
| <P>As of 1998 there are only a few software packages available which use the |
| DSO mechanism to actually extend their functionality at run-time: Perl 5 (via |
| its XS mechanism and the DynaLoader module), Netscape Server, <EM>etc.</EM> Starting |
| with version 1.3, Apache joined the crew, because Apache already uses a module |
| concept to extend its functionality and internally uses a dispatch-list-based |
| approach to link external modules into the Apache core functionality. So, |
| Apache is really predestined for using DSO to load its modules at run-time. |
| |
| <P>As of Apache 1.3, the configuration system supports two optional features |
| for taking advantage of the modular DSO approach: compilation of the Apache |
| core program into a DSO library for shared usage and compilation of the |
| Apache modules into DSO files for explicit loading at run-time. |
| |
| <H3>Implementation</H3> |
| |
| <P>The DSO support for loading individual Apache modules is based on a module |
| named <A HREF="mod/mod_so.html"><CODE>mod_so.c</CODE></A> which has to be |
| statically compiled into the Apache core. It is the only module besides |
| <CODE>http_core.c</CODE> which cannot be put into a DSO itself |
| (bootstrapping!). Practically all other distributed Apache modules then can |
| then be placed into a DSO by individually enabling the DSO build for them via |
| <CODE>configure</CODE>'s <CODE>--enable-shared</CODE> option (see top-level |
| <CODE>INSTALL</CODE> file) or by changing the <CODE>AddModule</CODE> command |
| in your <CODE>src/Configuration</CODE> into a <CODE>SharedModule</CODE> |
| command (see <CODE>src/INSTALL</CODE> file). After a module is compiled into |
| a DSO named <CODE>mod_foo.so</CODE> you can use <A |
| HREF="mod/mod_so.html"><CODE>mod_so</CODE></A>'s <A |
| HREF="mod/mod_so.html#loadmodule"><CODE>LoadModule</CODE></A> command in your |
| <CODE>httpd.conf</CODE> file to load this module at server startup or restart. |
| |
| <P>To simplify this creation of DSO files for Apache modules (especially for |
| third-party modules) a new support program named <CODE>apxs</CODE> (<EM>APache |
| eXtenSion</EM>) is available. It can be used to build DSO based modules |
| <EM>outside of</EM> the Apache source tree. The idea is simple: When |
| installing Apache the <CODE>configure</CODE>'s <CODE>make install</CODE> |
| procedure installs the Apache C header files and puts the platform-dependent |
| compiler and linker flags for building DSO files into the <CODE>apxs</CODE> |
| program. This way the user can use <CODE>apxs</CODE> to compile his Apache |
| module sources without the Apache distribution source tree and without having |
| to fiddle with the platform-dependent compiler and linker flags for DSO |
| support. |
| |
| <P>To place the complete Apache core program into a DSO library (only required |
| on some of the supported platforms to force the linker to export the apache |
| core symbols -- a prerequisite for the DSO modularization) the rule |
| <CODE>SHARED_CORE</CODE> has to be enabled via <CODE>configure</CODE>'s |
| <CODE>--enable-rule=SHARED_CORE</CODE> option (see top-level |
| <CODE>INSTALL</CODE> file) or by changing the <CODE>Rule</CODE> command in |
| your <CODE>Configuration</CODE> file to <CODE>Rule SHARED_CORE=yes</CODE> (see |
| <CODE>src/INSTALL</CODE> file). The Apache core code is then placed into a DSO |
| library named <CODE>libhttpd.so</CODE>. Because one cannot link a DSO against |
| static libraries on all platforms, an additional executable program named |
| <CODE>libhttpd.ep</CODE> is created which both binds this static code and |
| provides a stub for the <CODE>main()</CODE> function. Finally the |
| <CODE>httpd</CODE> executable program itself is replaced by a bootstrapping |
| code which automatically makes sure the Unix loader is able to load and start |
| <CODE>libhttpd.ep</CODE> by providing the <CODE>LD_LIBRARY_PATH</CODE> to |
| <CODE>libhttpd.so</CODE>. |
| |
| <H3>Supported Platforms</H3> |
| |
| <P>Apache's <CODE>src/Configure</CODE> script currently has only limited but |
| adequate built-in knowledge on how to compile DSO files, because as already |
| mentioned this is heavily platform-dependent. Nevertheless all major Unix |
| platforms are supported. The definitive current state (May 1999) is this: |
| |
| <P> |
| <UL> |
| <LI>Out-of-the-box supported platforms:<BR> |
| (actually tested versions in parenthesis) |
| |
| <PRE> |
| o FreeBSD (2.1.5, 2.2.x, 3.x, 4.x) |
| o OpenBSD (2.x) |
| o NetBSD (1.3.1) |
| o BSDI (3.x, 4.x) |
| o Linux (Debian/1.3.1, RedHat/4.2) |
| o Solaris (2.4, 2.5, 2.6, 2.7) |
| o SunOS (4.1.3) |
| o Digital UNIX (4.0) |
| o IRIX (5.3, 6.2) |
| o HP/UX (10.20) |
| o UnixWare (2.01, 2.1.2) |
| o SCO (5.0.4) |
| o AIX (3.2, 4.1.5, 4.2, 4.3) |
| o ReliantUNIX/SINIX (5.43) |
| o SVR4 (-) |
| o Mac OS X Server (1.0) |
| o Mac OS (10.0 preview 1) |
| o OpenStep/Mach (4.2) |
| o DGUX (??) |
| o NetWare (5.1) |
| </PRE> |
| |
| <P> |
| <LI> Explicitly unsupported platforms: |
| |
| <PRE> |
| o Ultrix (no dlopen-style interface under this platform) |
| </PRE> |
| |
| </UL> |
| |
| <H3>Usage Summary</H3> |
| |
| <P>To give you an overview of the DSO features of Apache 1.3, here is a short |
| and concise summary: |
| |
| <OL> |
| |
| <LI>Placing the Apache core code (all the stuff which usually forms the |
| <CODE>httpd</CODE> binary) into a DSO <CODE>libhttpd.so</CODE>, an executable |
| program <CODE>libhttpd.ep</CODE> and a bootstrapping executable program |
| <CODE>httpd</CODE> (Notice: this is only required on some of the supported |
| platforms to force the linker to export the Apache core symbols, which in turn |
| is a prerequisite for the DSO modularization): |
| |
| <P> |
| <UL> |
| <LI>Build and install via <CODE>configure</CODE> (preferred): |
| <TABLE BGCOLOR="#f0f0f0" CELLPADDING=10><TR><TD> |
| <PRE> |
| $ ./configure --prefix=/path/to/install |
| --enable-rule=SHARED_CORE ... |
| $ make install |
| </PRE> |
| </TD></TR></TABLE> |
| |
| <LI>Build and install manually: |
| <TABLE BGCOLOR="#f0f0f0" CELLPADDING=10><TR><TD> |
| <PRE> |
| - Edit src/Configuration: |
| << Rule SHARED_CORE=default |
| >> Rule SHARED_CORE=yes |
| << EXTRA_CFLAGS= |
| >> EXTRA_CFLAGS= -DSHARED_CORE_DIR=\"/path/to/install/libexec\" |
| $ make |
| $ cp src/libhttpd.so* /path/to/install/libexec/ |
| $ cp src/libhttpd.ep /path/to/install/libexec/ |
| $ cp src/httpd /path/to/install/bin/ |
| </PRE> |
| </TD></TR></TABLE> |
| </UL> |
| |
| <LI>Build and install a <EM>distributed</EM> Apache module, say |
| <CODE>mod_foo.c</CODE>, into its own DSO <CODE>mod_foo.so</CODE>: |
| |
| <P> |
| <UL> |
| <LI>Build and install via <CODE>configure</CODE> (preferred): |
| <TABLE BGCOLOR="#f0f0f0" CELLPADDING=10><TR><TD> |
| <PRE> |
| $ ./configure --prefix=/path/to/install |
| --enable-shared=foo |
| $ make install |
| </PRE> |
| </TD></TR></TABLE> |
| |
| <LI>Build and install manually: |
| <TABLE BGCOLOR="#f0f0f0" CELLPADDING=10><TR><TD> |
| <PRE> |
| - Edit src/Configuration: |
| << AddModule modules/xxxx/mod_foo.o |
| >> SharedModule modules/xxxx/mod_foo.so |
| $ make |
| $ cp src/xxxx/mod_foo.so /path/to/install/libexec |
| - Edit /path/to/install/etc/httpd.conf |
| >> LoadModule foo_module /path/to/install/libexec/mod_foo.so |
| </PRE> |
| </TD></TR></TABLE> |
| </UL> |
| |
| <LI>Build and install a <EM>third-party</EM> Apache module, say |
| <CODE>mod_foo.c</CODE>, into its own DSO <CODE>mod_foo.so</CODE> |
| |
| <P> |
| <UL> |
| <LI>Build and install via <CODE>configure</CODE> (preferred): |
| <TABLE BGCOLOR="#f0f0f0" CELLPADDING=10><TR><TD> |
| <PRE> |
| $ ./configure --add-module=/path/to/3rdparty/mod_foo.c |
| --enable-shared=foo |
| $ make install |
| </PRE> |
| </TD></TR></TABLE> |
| |
| <LI>Build and install manually: |
| <TABLE BGCOLOR="#f0f0f0" CELLPADDING=10><TR><TD> |
| <PRE> |
| $ cp /path/to/3rdparty/mod_foo.c /path/to/apache-1.3/src/modules/extra/ |
| - Edit src/Configuration: |
| >> SharedModule modules/extra/mod_foo.so |
| $ make |
| $ cp src/xxxx/mod_foo.so /path/to/install/libexec |
| - Edit /path/to/install/etc/httpd.conf |
| >> LoadModule foo_module /path/to/install/libexec/mod_foo.so |
| </PRE> |
| </TD></TR></TABLE> |
| </UL> |
| |
| <P> |
| <LI>Build and install a <EM>third-party</EM> Apache module, say |
| <CODE>mod_foo.c</CODE>, into its own DSO <CODE>mod_foo.so</CODE> <EM>outside |
| of</EM> the Apache source tree: |
| |
| <P> |
| <UL> |
| <LI>Build and install via <CODE>apxs</CODE>: |
| <TABLE BGCOLOR="#f0f0f0" CELLPADDING=10><TR><TD> |
| <PRE> |
| $ cd /path/to/3rdparty |
| $ apxs -c mod_foo.c |
| $ apxs -i -a -n foo mod_foo.so |
| </PRE> |
| </TD></TR></TABLE> |
| </UL> |
| |
| </OL> |
| |
| <H3>Advantages & Disadvantages</H3> |
| |
| <P>The above DSO based features of Apache 1.3 have the following advantages: |
| |
| <UL> |
| <LI> The server package is more flexible at run-time because the actual server |
| process can be assembled at run-time via <A |
| HREF="mod/mod_so.html#loadmodule"><CODE>LoadModule</CODE></A> |
| <CODE>httpd.conf</CODE> configuration commands instead of |
| <CODE>Configuration</CODE> <CODE>AddModule</CODE> commands at build-time. |
| For instance this way one is able to run different server instances |
| (standard & SSL version, minimalistic & powered up version |
| [mod_perl, PHP3], <EM>etc.</EM>) with only one Apache installation. |
| <P> |
| <LI> The server package can be easily extended with third-party modules even |
| after installation. This is at least a great benefit for vendor package |
| maintainers who can create a Apache core package and additional packages |
| containing extensions like PHP3, mod_perl, mod_fastcgi, <EM>etc.</EM> |
| <P> |
| <LI> Easier Apache module prototyping because with the DSO/<CODE>apxs</CODE> |
| pair you can both work outside the Apache source tree and only need an |
| <CODE>apxs -i</CODE> command followed by an <CODE>apachectl |
| restart</CODE> to bring a new version of your currently developed module |
| into the running Apache server. |
| </UL> |
| |
| <P>DSO has the following disadvantages: |
| |
| <UL> |
| <LI> The DSO mechanism cannot be used on every platform because not all |
| operating systems support dynamic loading of code into the address space |
| of a program. |
| <P> |
| <LI> The server is approximately 20% slower at startup time because of the |
| symbol resolving overhead the Unix loader now has to do. |
| <P> |
| <LI> The server is approximately 5% slower at execution time under some |
| platforms because position independent code (PIC) sometimes needs |
| complicated assembler tricks for relative addressing which are not |
| necessarily as fast as absolute addressing. |
| <P> |
| <LI> Because DSO modules cannot be linked against other DSO-based libraries |
| (<CODE>ld -lfoo</CODE>) on all platforms (for instance a.out-based |
| platforms usually don't provide this functionality while ELF-based |
| platforms do) you cannot use the DSO mechanism for all types of modules. |
| Or in other words, modules compiled as DSO files are restricted to only |
| use symbols from the Apache core, from the C library (<CODE>libc</CODE>) |
| and all other dynamic or static libraries used by the Apache core, or |
| from static library archives (<CODE>libfoo.a</CODE>) containing position |
| independent code. The only chances to use other code is to either make |
| sure the Apache core itself already contains a reference to it, loading |
| the code yourself via <CODE>dlopen()</CODE> or enabling the |
| <CODE>SHARED_CHAIN</CODE> rule while building Apache when your platform |
| supports linking DSO files against DSO libraries. |
| <P> |
| <LI> Under some platforms (many SVR4 systems) there is no way to force the |
| linker to export all global symbols for use in DSO's when linking the |
| Apache httpd executable program. But without the visibility of the Apache |
| core symbols no standard Apache module could be used as a DSO. The only |
| chance here is to use the <CODE>SHARED_CORE</CODE> feature because this |
| way the global symbols are forced to be exported. As a consequence the |
| Apache <CODE>src/Configure</CODE> script automatically enforces |
| <CODE>SHARED_CORE</CODE> on these platforms when DSO features are used in |
| the <CODE>Configuration</CODE> file or on the configure command line. |
| </UL> |
| |
| <!--#include virtual="footer.html" --> |
| </BLOCKQUOTE> |
| </BODY> |
| </HTML> |