http://blog.csdn.net/q_l_s/article/details/52594252
在linux中,程序的加載,涉及到兩個工具,linker 和loader。Linker主要涉及動態鏈接庫的使用,loader主要涉及軟件的加載。
1、 exec執行一個程序
2、 elf為現在非常流行的可執行文件的格式,它為程序運行划分了兩個段,一個段是可以執行的代碼段,它是只讀,可執行;另一個段是數據段,它是可讀寫,不能執行。
3、 loader會啟動,通過mmap系統調用,將代碼端和數據段映射到內存中,其實也就是為其分配了虛擬內存,注意這時候,還不占用物理內存;只有程序執行到了相應的地方,內核才會為其分配物理內存。
4、 loader會去查找該程序依賴的鏈接庫,首先看該鏈接庫是否被映射進內存中,如果沒有使用mmap,將代碼段與數據段映射到內存中,否則只是將其加入進程的地址空間。這樣比如glibc等庫的內存地址空間是完全一樣。
因此一個2M的程序,執行時,並不意味着為其分配了2M的物理內存,這與其運行了的代碼量,與其所依賴的動態鏈接庫有關。
運行過程中鏈接動態鏈接庫與編譯過程中鏈接動態庫的區別。
我們調用動態鏈接庫有兩種方法:一種是編譯的時候,指明所依賴的動態鏈接庫,這樣loader可以在程序啟動的時候,來所有的動態鏈接映射到內存中;一種是在運行過程中,通過dlopen和dlfree的方式加載動態鏈接庫,動態將動態鏈接庫加載到內存中。
這兩種方式,從編程角度來講,第一種是最方便的,效率上影響也不大,在內存使用上有些差別。
第一種方式,一個庫的代碼,只要運行過一次,便會占用物理內存,之后即使再也不使用,也會占用物理內存,直到進程的終止。
第二中方式,庫代碼占用的內存,可以通過dlfree的方式,釋放掉,返回給物理內存。
這個差別主要對於那些壽命很長,但又會偶爾調用各種庫的進程有關。如果是這類進程,建議采用第二種方式調用動態鏈接庫。
mmap()和vma相關和底層的驅動相關
如果用戶的空間映射到虛擬內存大塊的映射 用mmap
驅動需要做一個簡單的線性的設備內存映射, 到一個用戶地址空間, remap_pfn_range 幾乎是所有你做這個工作真正需要做的. 下列的代碼從 drivers/char/mem.c 中得來, 並且顯示了這個任務如何在一個稱為 simple ( Simple Implementation Mapping Pages with Little Enthusiasm)的典型模塊中進行的.
static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma) { if (remap_pfn_range(vma, vma->vm_start, vm->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; vma->vm_ops = &simple_remap_vm_ops; simple_vma_open(vma); return 0; }
如你所見, 重新映射內存只不過是調用 remap_pfn_rage 來創建必要的頁表.