Пункт 15. Поддержка динамических общих объектов (DSO)
HTTP-сервер Apache представляет собой модульную программу, в которой администратор может выбрать функциональные возможности для включения в сервер, выбрав набор модулей. Модули будут скомпилированы как динамические общие объекты (DSO), которые существуют отдельно от основного httpd
двоичного файла. Модули DSO могут быть скомпилированы во время сборки сервера или же они могут быть скомпилированы и добавлены позднее с помощью Apache Extension Tool ( apxs
).
Кроме того, модули могут быть статически скомпилированы в httpd
двоичный файл при сборке сервера.
Этот документ описывает, как использовать модули DSO, а также теорию их использования.
Выполнение
Поддержка DSO для загрузки отдельных модулей Apache httpd основана на имени модуля, mod_so
который должен быть статически скомпилирован в ядро Apache httpd. Это единственный модуль
core
, который нельзя поместить в сам DSO. Практически все другие распространяемые модули Apache httpd затем будут помещены в DSO. После того, как модуль скомпилирован в DSO с именем,
mod_foo.so
вы можете использовать директиву mod_so
's LoadModule
в вашем
apache2.conf
файле, чтобы загрузить этот модуль при запуске или перезапуске сервера.
Сборки DSO для отдельных модулей можно отключить с помощью
configure
параметра --enable-mods-static
, как описано в документации по установке.
Чтобы упростить создание файлов DSO для модулей Apache httpd (особенно для сторонних модулей), доступна программа поддержки с именем apxs
( APache eXtenSion ). Его можно использовать для создания модулей на основе DSO за пределами исходного дерева Apache httpd. Идея проста: при установке Apache HTTP Server configure
процедура
make install
устанавливает файлы заголовков Apache httpd C и помещает в программу флаги компилятора и компоновщика, зависящие от платформы, для создания файлов DSO apxs
. Таким образом, пользователь может использовать apxs
для компиляции своих исходных кодов модуля Apache httpd без исходного дерева дистрибутива Apache httpd и без необходимости возиться с зависимыми от платформы флагами компилятора и компоновщика для поддержки DSO.
Сводка по использованию
Чтобы дать вам обзор функций DSO Apache HTTP Server 2.x, вот краткое и краткое описание:
-
Соберите и установите распределенный модуль Apache httpd, скажем
mod_foo.c
, в свой собственный DSO
mod_foo.so
:
$ ./configure --prefix=/path/to/install --enable-foo
$ make install
-
Настройте HTTP-сервер Apache со всеми включенными модулями. При запуске сервера будет загружен только базовый набор. Вы можете изменить набор загружаемых модулей, активировав или деактивировав LoadModule
директивы в файлах
apache2.conf
.
$ ./configure --enable-mods-shared=all
$ make install
-
Некоторые модули полезны только для разработчиков и не будут собираться. при использовании модуля установить все . Чтобы собрать все доступные модули, включая модули разработчика, используйте файл realall . Кроме того,
LoadModule
директивы для всех встроенных модулей могут быть активированы с помощью опции конфигурации
--enable-load-all-modules
.
$ ./configure --enable-mods-shared=reallyall --enable-load-all-modules
$ make install
-
Создайте и установите сторонний модуль Apache httpd, скажем
mod_foo.c
, в свой собственный DSO
mod_foo.so
за пределами исходного дерева Apache httpd, используя apxs
:
$ cd /path/to/3rdparty
$ apxs -cia mod_foo.c
Во всех случаях, когда общий модуль скомпилирован, вы должны использовать директиву, LoadModule
чтобы apache2.conf
указать Apache httpd активировать модуль.
См. документацию apxs для более подробной информации.
Фон
В современных производных Unix существует механизм, называемый динамической компоновкой/загрузкой динамических общих объектов (DSO), который позволяет создавать фрагмент программного кода в специальном формате для его загрузки во время выполнения в адресное пространство исполняемой программы. .
Эта загрузка обычно может выполняться двумя способами: автоматически системной программой, вызываемой ld.so
при запуске исполняемой программы, или вручную из исполняемой программы через программный системный интерфейс к загрузчику Unix через системные вызовы
dlopen()/dlsym()
.
В первом случае DSO обычно называются разделяемыми библиотеками или библиотеками DSO и называются
libfoo.so
или libfoo.so.1.2
. Они находятся в системном каталоге (обычно /usr/lib
), а ссылка на исполняемую программу устанавливается во время сборки путем указания -lfoo
команды компоновщика. Эта библиотека жестко кодирует ссылки на исполняемый программный файл, чтобы во время запуска загрузчик 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 получает информацию о наборе символов исполняемой программы, как если бы он был статически связан с ним в первую очередь.
Наконец, чтобы воспользоваться преимуществами API DSO, исполняемая программа должна разрешать определенные символы из DSO через
dlsym()
для последующего использования в таблицах диспетчеризации
и т. д. Другими словами: исполняемая программа должна вручную разрешать каждый символ, который ей нужен, чтобы иметь возможность его использовать. . Преимущество такого механизма в том, что необязательные части программы не нужно загружать (и, следовательно, не тратить память), пока они не потребуются рассматриваемой программе. При необходимости эти части программы могут загружаться динамически для расширения функциональности базовой программы.
Хотя этот механизм DSO кажется простым, здесь есть по крайней мере один сложный шаг: разрешение символов из исполняемой программы для DSO при использовании DSO для расширения программы (второй способ). Почему? Потому что «обратное разрешение» символов DSO из набора символов исполняемой программы противоречит дизайну библиотеки (когда библиотека не знает о программах, которыми она используется) и недоступна ни для всех платформ, ни стандартизирована. На практике глобальные символы исполняемой программы часто не реэкспортируются и поэтому недоступны для использования в DSO. Поиск способа заставить компоновщик экспортировать все глобальные символы — основная проблема, которую необходимо решить при использовании DSO для расширения программы во время выполнения.
Подход с разделяемыми библиотеками является типичным, потому что именно для него был разработан механизм DSO, поэтому он используется почти для всех типов библиотек, предоставляемых операционной системой.
Преимущества и недостатки
Вышеупомянутые функции на основе DSO имеют следующие преимущества:
- Пакет сервера является более гибким во время выполнения, потому что серверный процесс может быть собран во время выполнения с помощью
LoadModule
apache2.conf
директив конфигурации, а не
configure
параметров во время сборки. Например, таким образом можно запускать разные экземпляры сервера (стандартную версию и версию SSL, минималистическую и динамическую версию [mod_perl, mod_php] и т. д. ) только с одной установкой Apache httpd.
- Серверный пакет можно легко расширить сторонними модулями даже после установки. Это большое преимущество для сопровождающих пакетов поставщиков, которые могут создавать основной пакет Apache httpd и дополнительные пакеты, содержащие расширения, такие как PHP, mod_perl, mod_security и т. д .
- Более простое прототипирование модуля Apache httpd, поскольку с помощью пары DSO/
apxs
вы можете работать вне исходного дерева Apache httpd и вам нужна только команда, apxs -i
за которой следует , apache2ctl restart
чтобы перенести новую версию вашего модуля, разработанного в настоящее время, на работающий HTTP-сервер Apache.
ДСО имеет следующие недостатки:
- Сервер работает примерно на 20 % медленнее во время запуска из-за того, что теперь загрузчик Unix должен выполнять накладные расходы на разрешение символов.
- Сервер примерно на 5% медленнее во время выполнения на некоторых платформах, потому что позиционно-независимый код (PIC) иногда требует сложных приемов ассемблера для относительной адресации, которые не обязательно так же быстры, как абсолютная адресация.
- Поскольку модули DSO не могут быть связаны с другими библиотеками на основе DSO (
ld -lfoo
) на всех платформах (например, платформы на основе a.out обычно не предоставляют эту функциональность, в отличие от платформ на основе ELF), вы не можете использовать механизм DSO для всех типов модули. Или, другими словами, модули, скомпилированные как файлы DSO, могут использовать только символы из ядра Apache httpd, из библиотеки C ( ) libc
и всех других динамических или статических библиотек, используемых ядром Apache httpd, или из архивов статических библиотек ( libfoo.a
), содержащих позиционно-независимый код. Единственная возможность использовать другой код — либо убедиться, что само ядро httpd уже содержит ссылку на него, либо загрузить код самостоятельно через dlopen()
.