可执行程序加载到内存的过程
在linux中,程序的加載,涉及到兩個(gè)工具,linker 和loader。Linker主要涉及動態(tài)鏈接庫的使用,loader主要涉及軟件的加載。
1、??exec執(zhí)行一個(gè)程序
2、??elf為現(xiàn)在非常流行的可執(zhí)行文件的格式,它為程序運(yùn)行劃分了兩個(gè)段,一個(gè)段是可以執(zhí)行的代碼段,它是只讀,可執(zhí)行;另一個(gè)段是數(shù)據(jù)段,它是可讀寫,不能執(zhí)行。
3、??loader會啟動,通過mmap系統(tǒng)調(diào)用,將代碼端和數(shù)據(jù)段映射到內(nèi)存中,其實(shí)也就是為其分配了虛擬內(nèi)存,注意這時(shí)候,還不占用物理內(nèi)存;只有程序執(zhí)行到了相應(yīng)的地方,內(nèi)核才會為其分配物理內(nèi)存。
4、??loader會去查找該程序依賴的鏈接庫,首先看該鏈接庫是否被映射進(jìn)內(nèi)存中,如果沒有使用mmap,將代碼段與數(shù)據(jù)段映射到內(nèi)存中,否則只是將其加入進(jìn)程的地址空間。這樣比如glibc等庫的內(nèi)存地址空間是完全一樣。
因此一個(gè)2M的程序,執(zhí)行時(shí),并不意味著為其分配了2M的物理內(nèi)存,這與其運(yùn)行了的代碼量,與其所依賴的動態(tài)鏈接庫有關(guān)。
運(yùn)行過程中鏈接動態(tài)鏈接庫與編譯過程中鏈接動態(tài)庫的區(qū)別。
我們調(diào)用動態(tài)鏈接庫有兩種方法:一種是編譯的時(shí)候,指明所依賴的動態(tài)鏈接庫,這樣loader可以在程序啟動的時(shí)候,來所有的動態(tài)鏈接映射到內(nèi)存中;一種是在運(yùn)行過程中,通過dlopen和dlfree的方式加載動態(tài)鏈接庫,動態(tài)將動態(tài)鏈接庫加載到內(nèi)存中。
這兩種方式,從編程角度來講,第一種是最方便的,效率上影響也不大,在內(nèi)存使用上有些差別。
第一種方式,一個(gè)庫的代碼,只要運(yùn)行過一次,便會占用物理內(nèi)存,之后即使再也不使用,也會占用物理內(nèi)存,直到進(jìn)程的終止。
第二中方式,庫代碼占用的內(nèi)存,可以通過dlfree的方式,釋放掉,返回給物理內(nèi)存。
這個(gè)差別主要對于那些壽命很長,但又會偶爾調(diào)用各種庫的進(jìn)程有關(guān)。如果是這類進(jìn)程,建議采用第二種方式調(diào)用動態(tài)鏈接庫。
?
mmap()和vma相關(guān)和底層的驅(qū)動相關(guān)
如果用戶的空間映射到虛擬內(nèi)存大塊的映射 用mmap
驅(qū)動需要做一個(gè)簡單的線性的設(shè)備內(nèi)存映射, 到一個(gè)用戶地址空間, remap_pfn_range 幾乎是所有你做這個(gè)工作真正需要做的. 下列的代碼從 drivers/char/mem.c 中得來, 并且顯示了這個(gè)任務(wù)如何在一個(gè)稱為 simple ( Simple Implementation Mapping Pages with Little Enthusiasm)的典型模塊中進(jìn)行的.
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; }如你所見, 重新映射內(nèi)存只不過是調(diào)用 remap_pfn_rage 來創(chuàng)建必要的頁表.
總結(jié)
以上是生活随笔為你收集整理的可执行程序加载到内存的过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序的重定位问题(程序装入)
- 下一篇: 性能优化CPU、内存、磁盘I/O、网络性