Apache動(dòng)態(tài)共享對象(DSO)支持

2021-10-13 18:21 更新
Apache HTTP Server是一個(gè)模塊化程序,管理員可以通過選擇一組模塊來選擇要包含在服務(wù)器中的功能。模塊將編譯為動(dòng)態(tài)共享對象(DSO),與主httpd二進(jìn)制文件分開存在。DSO模塊可以在構(gòu)建服務(wù)器時(shí)進(jìn)行編譯,也可以在以后使用Apache Extension Tool(apxs)進(jìn)行編譯和添加?;蛘?,可以在構(gòu)建服務(wù)器時(shí)將模塊靜態(tài)編譯為httpd二進(jìn)制文件。

本文檔介紹了如何使用DSO模塊及其使用背后的理論。

DSO支持的實(shí)現(xiàn)

DSO對加載單個(gè)Apache httpd模塊的支持基于名為mod_so的模塊,該模塊必須靜態(tài)編譯到Apache httpd核心中。除了核心之外,它是唯一不能放入DSO本身的模塊。實(shí)際上,所有其他分布式Apache httpd模塊將被放入DSO中。將模塊編譯為名為mod_foo.so的DSO后,可以在httpd.conf文件中使用mod_soLoadModule指令在服務(wù)器啟動(dòng)或重新啟動(dòng)時(shí)加載此模塊。

可以通過configure命令的--enable-mods-static選項(xiàng)禁用單個(gè)模塊的DSO構(gòu)建,如安裝文檔中所述。

為了簡化Apache httpd模塊(尤其是第三方模塊)的DSO文件的創(chuàng)建,可以使用名為apxs(APache eXtenSion)的支持程序。它可用于在Apache httpd源樹之外構(gòu)建基于DSO的模塊。這個(gè)想法很簡單:在安裝Apache HTTP Server時(shí),configure的make install過程會(huì)安裝Apache httpd C頭文件,并將用于構(gòu)建DSO文件的平臺(tái)相關(guān)編譯器和鏈接器標(biāo)志放入apxs程序中。這樣,用戶可以使用apxs編譯他的Apache httpd模塊源代碼,而無需Apache httpd分發(fā)源代碼樹,也無需為DSO支持提供依賴于平臺(tái)的編譯器和鏈接器標(biāo)志。

使用摘要

為了概述Apache HTTP Server 2.x的DSO功能,這里有一個(gè)簡短的摘要(步驟):

第1步 - 構(gòu)建并將分布式Apache httpd模塊(例如mod_foo.c)安裝到自己的DSO mod_foo.so中:

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

第2步 - 配置Apache HTTP Server并啟用所有模塊。服務(wù)器啟動(dòng)期間僅加載基本集??梢酝ㄟ^激活或取消激活httpd.conf中的LoadModule指令來更改已加載模塊的集合。

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

第3步 - 有些模塊僅對開發(fā)人員有用,不會(huì)構(gòu)建。使用模塊時(shí)全部設(shè)置。要構(gòu)建所有可用的模塊,包括開發(fā)人員模塊都可使用。此外,可以通過configure--enable-load-all-modules選項(xiàng)激活所有構(gòu)建模塊的LoadModule指令。

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

使用apxs在Apache httpd源代碼樹之外構(gòu)建并安裝第三方Apache httpd模塊(例如mod_foo.c)到其自己的DSO mod_foo.so中:

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

在所有情況下,一旦編譯了共享模塊,就必須在httpd.conf中使用LoadModule指令來告訴Apache httpd激活模塊。

背后機(jī)制

在現(xiàn)代Unix衍生產(chǎn)品中,存在一種稱為動(dòng)態(tài)共享對象(DSO)的動(dòng)態(tài)鏈接/加載機(jī)制,它提供了一種以特殊格式構(gòu)建程序代碼的方法,以便在運(yùn)行時(shí)將其加載到可執(zhí)行程序的地址空間中。

這種加載通??梢酝ㄟ^兩種方式完成:當(dāng)一個(gè)可執(zhí)行程序啟動(dòng)時(shí),通過一個(gè)名為ld.so的系統(tǒng)程序自動(dòng)完成,或者通過系統(tǒng)調(diào)用dlopen()/dlsym()通過編程系統(tǒng)接口從Unix加載器手動(dòng)執(zhí)行程序。

在第一種方式中,DSO通常稱為共享庫或DSO庫,并命名為libfoo.solibfoo.so.1.2。它們駐留在系統(tǒng)目錄(通常是/usr/lib)中,并且通過在鏈接器命令中指定-lfoo,在構(gòu)建時(shí)建立可執(zhí)行程序的鏈接。這個(gè)硬編碼庫引用了可執(zhí)行程序文件,因此在啟動(dòng)時(shí),Unix加載器能夠在/usr/lib中找到libfoo.so,在通過鏈接器選項(xiàng)(如-R)進(jìn)行硬編碼的路徑中,或者在通過環(huán)境變量LD_LIBRARY_PATH。然后它解析可執(zhí)行程序中可用于DSO的任何(尚未解決的)符號。

可執(zhí)行程序中的符號通常不會(huì)被DSO引用(因?yàn)樗强芍赜玫耐ㄓ么a庫),因此不需要進(jìn)一步解析??蓤?zhí)行程序不需要自己做任何事情來使用DSO中的符號,因?yàn)橥暾慕馕鍪怯蒛nix加載器完成的。實(shí)際上,調(diào)用ld.so的代碼是運(yùn)行時(shí)啟動(dòng)代碼的一部分,該代碼鏈接到已經(jīng)綁定為非靜態(tài)的每個(gè)可執(zhí)行程序。動(dòng)態(tài)加載公共庫代碼的優(yōu)勢顯而易見:庫代碼只需要存儲(chǔ)一次,就像libc.so這樣的系統(tǒng)庫,為每個(gè)程序節(jié)省磁盤空間。

在第二種方式中,DSO通常稱為共享對象或DSO文件,并且可以使用任意擴(kuò)展名命名(盡管規(guī)范名稱為foo.so)。這些文件通常保留在特定于程序的目錄中,并且沒有自動(dòng)建立的鏈接指向使用它們的可執(zhí)行程序。相反,可執(zhí)行程序通過dlopen()手動(dòng)將DSO在運(yùn)行時(shí)加載到其地址空間。此時(shí),不會(huì)從DSO解析可執(zhí)行程序的符號。但是,Unix加載程序會(huì)自動(dòng)解析DSO中可執(zhí)行程序?qū)С龅姆柤捌湟鸭虞d的DSO庫(尤其是來自無處不在的libc.so的所有符號)中的任何(尚未解析的)符號。通過這種方式,DSO可以了解可執(zhí)行程序的符號集,就好像它首先與它靜態(tài)鏈接一樣。

最后,為了利用DSO的API,可執(zhí)行程序必須通過dlsym()解析DSO中的特定符號,以便以后在調(diào)度表等內(nèi)部使用。換句話說:可執(zhí)行程序必須手動(dòng)解析它需要的每個(gè)符號才能使用它。這種機(jī)制的優(yōu)點(diǎn)在于,在所討論的程序需要它們之前,不需要加載可選的程序部分(因此不需要花費(fèi)內(nèi)存)。必要時(shí),可以動(dòng)態(tài)加載這些程序部分以擴(kuò)展基本程序的功能。

盡管這種DSO機(jī)制聽起來很簡單,但至少有一個(gè)困難的步驟:當(dāng)使用DSO擴(kuò)展程序時(shí),從DSO的可執(zhí)行程序中解析符號(第二種方式)。為什么?因?yàn)閬碜钥蓤?zhí)行程序符號集的“反向解析”DSO符號是針對庫設(shè)計(jì)的(庫不知道它所使用的程序),并且既不是在所有平臺(tái)上都可用,也不是標(biāo)準(zhǔn)化的。實(shí)際上,可執(zhí)行程序的全局符號通常不會(huì)重新導(dǎo)出,因此無法在DSO中使用。找到一種強(qiáng)制鏈接器導(dǎo)出所有全局符號的方法是使用DSO在運(yùn)行時(shí)擴(kuò)展程序時(shí)必須解決的主要問題。

共享庫方法是典型的方法,因?yàn)樗荄SO機(jī)制的設(shè)計(jì)方法,因此它幾乎用于操作系統(tǒng)提供的所有類型的庫。

DSO優(yōu)點(diǎn)和缺點(diǎn)

基于DSO的功能具有以下優(yōu)點(diǎn):

  • 服務(wù)器包在運(yùn)行時(shí)更靈活,因?yàn)榉?wù)器進(jìn)程可以在運(yùn)行時(shí)通過httpd.conf配置 LoadModule 指令而不是在構(gòu)建時(shí)配置選項(xiàng)進(jìn)行組裝。例如,通過這種方式,只需一個(gè)Apache httpd安裝即可運(yùn)行不同的服務(wù)器實(shí)例(標(biāo)準(zhǔn)版和SSL版,簡約版和動(dòng)態(tài)版[mod_perl,mod_php]等)。
  • 即使在安裝后,也可以使用第三方模塊輕松擴(kuò)展服務(wù)器包。這對于供應(yīng)商軟件包維護(hù)者來說是一個(gè)很大的好處,他們可以創(chuàng)建Apache httpd核心軟件包以及包含PHP,mod_perl,mod_security等擴(kuò)展的其他軟件包。
  • 更簡單的Apache httpd模塊原型設(shè)計(jì),因?yàn)槭褂肈SO/apxs對,可以在Apache httpd源樹之外工作,只需要apxs -i命令,然后重啟apachectl,即可將當(dāng)前開發(fā)的模塊的新版本帶入正在運(yùn)行的Apache HTTP服務(wù)器。

DSO具有以下缺點(diǎn):

  • 由于Unix加載器現(xiàn)在必須執(zhí)行的符號解決開銷,服務(wù)器在啟動(dòng)時(shí)的速度大約慢20%。
  • 在某些平臺(tái)下,服務(wù)器在執(zhí)行時(shí)的速度大約慢5%,因?yàn)槲恢脽o關(guān)代碼(PIC)有時(shí)需要復(fù)雜的匯編器技巧來進(jìn)行相對尋址,這不一定和絕對尋址一樣快。
  • 由于DSO模塊無法在所有平臺(tái)上與其他基于DSO的庫(ld -lfoo)鏈接(例如,基于a.out的平臺(tái)通常不提供此功能,而基于ELF的平臺(tái)),因此無法使用DSO機(jī)制所有類型的模塊?;蛘邠Q句話說,編譯為DSO文件的模塊僅限于使用來自Apache httpd核心,C庫(libc)以及Apache httpd核心使用的所有其他動(dòng)態(tài)或靜態(tài)庫或靜態(tài)庫歸檔(libfoo.a)包含與位置無關(guān)的代碼。使用其他代碼的唯一機(jī)會(huì)是確保httpd核心本身已包含對它的引用或通過dlopen()自己加載代碼。





以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號