2012-01-15 86 views
15

假設我在Linux中有一個使用共享庫的應用程序(.so文件)。我的問題是,這些庫中的代碼是否會在主應用程序的堆中分配內存,還是使用自己的堆?共享庫是否與應用程序使用相同的堆?

因此,例如,.so文件中的某些函數調用malloc,它會使用與應用程序相同的堆管理器還是另一個?另外,那些共享內存中的全局數據呢?它在哪裏呢?我知道它的應用程序位於bss和數據段,但不知道這些共享對象文件的位置。

+0

您是否問與共享庫的部分是否與原始可執行文件的部分聚合動態鏈接? – 2012-01-15 01:17:44

+1

共享庫BSS和數據段將與應用程序的其餘BSS和數據段在某種程度上分開,但這些都是由系統爲您處理的。 – 2012-01-15 02:25:55

回答

25

我的問題是這些庫中的代碼是否會在與主應用程序相同的堆中分配內存,或者它們是否使用自己的堆?

如果庫使用相同malloc/free作爲應用程序(例如,來自glibc) - 然後是,程序和所有庫將使用單個堆。

如果庫直接使用mmap,它可以分配不是程序自身使用的內存的內存。

因此,例如,.so文件中的某些函數調用malloc,它會使用與應用程序相同的堆管理器還是另一個?

如果.so函數調用malloc,則此malloc與從程序調用的malloc相同。你可以看到符號在Linux中綁定日誌/ glibc的(> 2.1)與

LD_DEBUG=bindings ./your_program 

是,堆管理器的多個實例(使用默認配置)不知道對方(這個問題是不能共存保持brk分配的堆大小在實例之間同步)。但是有幾個實例可以共存的配置。

最經典的malloc實現(ptmalloc *,dlmalloc等)可以使用兩種獲取系統內存的方法:brkmmap。 Brk是經典堆,它是線性的,可以增長或縮小。 Mmap允許在任何地方獲得大量內存;並且您可以以任何順序將此內存返回給系統(釋放它)。

當構建malloc時,可以禁用brk方法。然後,malloc將僅使用mmap s模擬線性堆,甚至會禁用經典線性堆,並且所有分配都將由不連續的虛擬碎片組成。

因此,某些圖書館可以擁有自己的內存管理器,例如, malloc編譯爲brk已禁用或使用非malloc內存管理器。此管理器應具有除mallocfree以外的函數名稱,例如malloc1free1,或者不應將此名稱顯示/導出到動態鏈接器。

另外,那些共享內存中的全局數據呢?它在哪裏呢?我知道它的應用程序位於bss和數據段,但不知道這些共享對象文件的位置。

你應該考慮關於程序和.so就像ELF文件一樣。每個ELF文件都有「程序標題」(readelf -l elf_file)。數據從ELF加載到內存的方式取決於程序頭的類型。如果類型爲「LOAD」,則文件的相應部分將私密地存儲到內存中。通常,有2個LOAD段;第一個用於R + X(讀取+執行)標誌的代碼,第二個用於R + W(讀取+寫入)標誌的數據。 .bss.data(全局數據)部分都放在LOAD類型的段中,並帶有寫使能標誌。

可執行文件和共享庫都有LOAD段。一些段具有memory_size> file_size。這意味着該分段將在內存中擴展;它的第一部分將被填充有從ELF文件和大小(memory_size-FILE_SIZE)的所述第二部分中的數據將被填充零(爲*bss部分),採用mmap(/dev/zero)memset(0)

當內核或動態鏈接程序加載ELF將文件存入內存,他們不會考慮共享。例如,您想要兩次啓動相同的程序。第一個進程將使用mmap加載ELF文件的只讀部分;第二個進程將執行相同的mmap(如果aslr處於活動狀態 - 第二個mmap將進入不同的虛擬地址)。它是頁面緩存(VFS子系統)的任務,用於將單個數據副本保留在物理內存中(使用COPY-WRITE也稱爲COW);而mmap只會將每個進程中的虛擬地址映射到單個物理位置。如果有任何進程會改變內存頁面;它會在寫入唯一私有物理內存時被複制。

加載代碼爲glibc/elf/dl-load.c_dl_map_object_from_fd)爲ld.so和linux-kernel/fs/binfmt_elf.c爲內核的ELF裝載機(elf_mapload_elf_binary)。搜索PT_LOAD

因此,全局數據和bss數據總是在每個進程中進行私有配置,並且使用COW進行保護。

堆和棧在運行時用brk + mmap(heap)和OS內核在類似brk的進程(用於主線程堆棧)中自動分配。其他線程的堆棧在pthread_create中分配爲mmap

+0

謝謝,你的回答非常有幫助。 – MetallicPriest 2012-01-15 10:32:03

+0

MetallicPriest,哪一部分更有幫助? – osgx 2012-01-15 10:56:48

+0

osgx - 第二個更有幫助。 – MetallicPriest 2012-01-15 15:32:01

8

符號表在Linux中的整個進程中共享。 malloc()該過程的任何部分與所有其他部分相同。所以是的,如果一個進程的所有部分通過malloc()等訪問堆,那麼他們將共享相同的堆。

+0

+1我們可能會提到在malloc的上下文之外調用brk,以及這樣做的後果。您可以讓部分庫代碼和本地代碼不「知道」現有的堆邊界。分類的精神分裂症堆。不好。 – 2012-01-15 03:29:01

+0

malloc可以通過'brk'和'mmap'分配內存。只有malloc庫的單個實例可以用brk管理內存;但是如果有另一個malloc實例被鏈接,它可以使用mmap來模擬單獨的堆。 – osgx 2012-01-15 09:21:57

相關問題