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

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

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

DSO支持的實現(xiàn)

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

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

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

使用摘要

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

第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并啟用所有模塊。服務器啟動期間僅加載基本集??梢酝ㄟ^激活或取消激活httpd.conf中的LoadModule指令來更改已加載模塊的集合。

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

第3步 - 有些模塊僅對開發(fā)人員有用,不會構(gòu)建。使用模塊時全部設置。要構(gòu)建所有可用的模塊,包括開發(fā)人員模塊都可使用。此外,可以通過configure--enable-load-all-modules選項激活所有構(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激活模塊。

背后機制

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

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

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

可執(zhí)行程序中的符號通常不會被DSO引用(因為它是可重用的通用代碼庫),因此不需要進一步解析??蓤?zhí)行程序不需要自己做任何事情來使用DSO中的符號,因為完整的解析是由Unix加載器完成的。實際上,調(diào)用ld.so的代碼是運行時啟動代碼的一部分,該代碼鏈接到已經(jīng)綁定為非靜態(tài)的每個可執(zhí)行程序。動態(tài)加載公共庫代碼的優(yōu)勢顯而易見:庫代碼只需要存儲一次,就像libc.so這樣的系統(tǒng)庫,為每個程序節(jié)省磁盤空間。

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

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

盡管這種DSO機制聽起來很簡單,但至少有一個困難的步驟:當使用DSO擴展程序時,從DSO的可執(zhí)行程序中解析符號(第二種方式)。為什么?因為來自可執(zhí)行程序符號集的“反向解析”DSO符號是針對庫設計的(庫不知道它所使用的程序),并且既不是在所有平臺上都可用,也不是標準化的。實際上,可執(zhí)行程序的全局符號通常不會重新導出,因此無法在DSO中使用。找到一種強制鏈接器導出所有全局符號的方法是使用DSO在運行時擴展程序時必須解決的主要問題。

共享庫方法是典型的方法,因為它是DSO機制的設計方法,因此它幾乎用于操作系統(tǒng)提供的所有類型的庫。

DSO優(yōu)點和缺點

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

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

DSO具有以下缺點:

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





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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號