日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

程序员的自我修养六可执行文件的装载与进程

發(fā)布時(shí)間:2024/4/17 编程问答 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员的自我修养六可执行文件的装载与进程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

可執(zhí)行文件只有裝載到內(nèi)存以后才能被CPU執(zhí)行

6.1進(jìn)程虛擬地址空間

程序和進(jìn)程的區(qū)別:
程序:是一個(gè)靜態(tài)概念,它就是一些預(yù)先編譯好的指令和數(shù)據(jù)集合的一個(gè)文件。
進(jìn)程:是一個(gè)動(dòng)態(tài)概念,它是程序運(yùn)行時(shí)的一個(gè)過(guò)程,很多時(shí)候把動(dòng)態(tài)庫(kù)叫做運(yùn)行時(shí)。
程序被運(yùn)行起來(lái)以后,它就擁有了獨(dú)立的虛擬地址空間。虛擬地址空間大小由CPU的位數(shù)決定。
下面使用的CUP都是以32位為主。程序運(yùn)行的時(shí)候,進(jìn)程只能使用那些操作系統(tǒng)分配給進(jìn)程的地址。
Linux操作系統(tǒng)將進(jìn)程的虛擬地址做了如下分配:

6.2 裝載的方式

程序執(zhí)行時(shí)所需要的指令和數(shù)據(jù)必須在內(nèi)存中才能夠運(yùn)行。
最簡(jiǎn)單的就是靜態(tài)裝入:將程序運(yùn)行所需要的指令和數(shù)據(jù)全都裝入內(nèi)存中。
當(dāng)當(dāng)程序所需要內(nèi)存大于物理內(nèi)存時(shí),這個(gè)時(shí)候就要使用動(dòng)態(tài)裝入了:因?yàn)槌绦蜻\(yùn)行時(shí)是有局部性原理的,所以我們將程序最常用的部分駐留在內(nèi)存中,不太常用的數(shù)據(jù)存放在磁盤里面。
動(dòng)態(tài)裝入的兩種方法:

  • 覆蓋裝入
  • 頁(yè)映射

6.2.1 覆蓋裝入

覆蓋裝入在沒(méi)有發(fā)明虛擬存儲(chǔ)之前使用比較廣泛,現(xiàn)在已經(jīng)幾乎被淘汰。
覆蓋裝入的方法就是程序員在編寫程序的時(shí)候必須手工將程序分割成若干塊,然后編寫一個(gè)小的輔助代碼來(lái)管理這些模塊何時(shí)應(yīng)該駐留內(nèi)存何時(shí)應(yīng)該被替換掉。
如果程序有多個(gè)模塊,程序員需要手工將模塊按照它們之間的調(diào)用依賴關(guān)系組織成樹(shù)狀結(jié)構(gòu)

6.2.2 頁(yè)映射

頁(yè)映射是虛擬存儲(chǔ)機(jī)制的一部分,它隨著虛擬存儲(chǔ)的發(fā)明而誕生。
頁(yè)映射就是將內(nèi)存和所有磁盤中的數(shù)據(jù)和指令按照頁(yè)為單位劃分成若干個(gè)頁(yè),以后所有的轉(zhuǎn)載和操作的單位就是頁(yè)。硬件規(guī)定頁(yè)的大小有4096字節(jié)、8192字節(jié)、2MB、4MB等。

6.3 從操作系統(tǒng)的角度看可執(zhí)行文件的裝載

在動(dòng)態(tài)裝載中,可執(zhí)行文件中的頁(yè)可能被裝入內(nèi)存中的任意頁(yè)。

6.3.1 進(jìn)程的建立

從操作系統(tǒng)的角度看,一個(gè)進(jìn)程最關(guān)鍵的特征是它擁有獨(dú)立的虛擬地址空間,這使得它有別于其他進(jìn)程。
程序創(chuàng)建的最通常情況:創(chuàng)建一個(gè)進(jìn)程,然后裝載相應(yīng)的可執(zhí)行文件并且執(zhí)行。
在有虛擬存儲(chǔ)的情況下,上述過(guò)程只需要要做三件事:

  • 創(chuàng)建一個(gè)獨(dú)立的虛擬地址空間
  • 讀取可執(zhí)行文件頭,并且建立虛擬空間與可執(zhí)行文件的映射關(guān)系
  • 將CPU的指令寄存器設(shè)置成可執(zhí)行文件的入口地址,啟動(dòng)運(yùn)行

首先創(chuàng)建虛擬地址空間:創(chuàng)建一個(gè)虛擬地址空間并不是創(chuàng)建空間而是創(chuàng)建映射函數(shù)所需要的數(shù)據(jù)結(jié)構(gòu)。
讀取可執(zhí)行文件頭,并且建立虛擬空間與可執(zhí)行文件的映射關(guān)系:當(dāng)程序發(fā)生頁(yè)錯(cuò)誤的時(shí)候,操作系統(tǒng)將從物理內(nèi)存中分配一個(gè)物理頁(yè),然后將該”缺頁(yè)”從磁盤中讀取到內(nèi)存中,再設(shè)置缺頁(yè)的虛擬頁(yè)和物理頁(yè)的映射關(guān)系。當(dāng)操作系統(tǒng)捕獲到缺頁(yè)錯(cuò)誤時(shí),它應(yīng)知道程序當(dāng)前所需要的頁(yè)在可執(zhí)行文件中的哪一個(gè)位置。這就是虛擬空間與可執(zhí)行文件之間的映射關(guān)系。Linux中將進(jìn)程虛擬空間中的一個(gè)段叫做虛擬內(nèi)存區(qū)域,在Windows中將這個(gè)叫做”虛擬段”。
將CPU指令寄存器設(shè)置成可執(zhí)行文件入口,啟動(dòng)運(yùn)行:操作系統(tǒng)通過(guò)設(shè)置CPU的指令寄存器將控制權(quán)交給進(jìn)程,由此進(jìn)程開(kāi)始執(zhí)行。

6.3.2 頁(yè)錯(cuò)誤

當(dāng)CPU開(kāi)始打算執(zhí)行一個(gè)地址指令時(shí),發(fā)現(xiàn)頁(yè)面是空頁(yè)面,于是它認(rèn)為這是一個(gè)頁(yè)錯(cuò)誤。CPU將控制權(quán)交給操作系統(tǒng),操作系統(tǒng)將查詢第二步建立的數(shù)據(jù)結(jié)構(gòu),然后找到VMA,計(jì)算出相應(yīng)的頁(yè)面在可執(zhí)行文件中的偏移,然后在物理內(nèi)存中分配一個(gè)物理頁(yè)面,將進(jìn)程中該虛擬頁(yè)與分配的物理頁(yè)之間建立映射關(guān)系,然后把控制權(quán)交回給進(jìn)程,進(jìn)程從剛才錯(cuò)誤頁(yè)位置重新開(kāi)始執(zhí)行。

6.4 進(jìn)程虛存空間分布

6.4.1 ELF文件鏈接視圖和執(zhí)行視圖

前面的例子的可執(zhí)行文件只有一個(gè)代碼段,所有它被操作系統(tǒng)轉(zhuǎn)載至進(jìn)程地址空間之后,相對(duì)應(yīng)的只有一個(gè)VMA。
當(dāng)段的數(shù)量增多時(shí),就會(huì)產(chǎn)生空間浪費(fèi)問(wèn)題。為了避免這種問(wèn)題,可以把相同的段合并。
操作系統(tǒng)至關(guān)心段的權(quán)限(可讀,可寫,可執(zhí)行)。
ELF文件中,段的權(quán)限基本是三種:

  • 以代碼段為代表的權(quán)限可讀可執(zhí)行的段
  • 以數(shù)據(jù)段和BSS段為代碼的權(quán)限為可讀可寫的段
  • 以只讀數(shù)據(jù)為代表的權(quán)限為只讀的段

一個(gè)簡(jiǎn)單的方案:對(duì)于相同權(quán)限的段,把它們合并到一起當(dāng)作一個(gè)段進(jìn)行映射。
一個(gè)”Segment”包含一個(gè)或多個(gè)屬性類似的”Section”。
從鏈接的角度看,ELF文件是按”Section”存儲(chǔ)的,從裝載的角度看ELF文件又可以按照”Segment”劃分。
“Section”和”Segment”是從不同角度來(lái)劃分同一個(gè)ELF文件的。這個(gè)在ELF種被稱為視圖,從”Section”的角度來(lái)看ELF文件就是鏈接視圖,從”Segment”的角度來(lái)看就是執(zhí)行視圖

?

?ELF可執(zhí)行文件中有一個(gè)專門的數(shù)據(jù)結(jié)構(gòu)叫做程序頭表用來(lái)保存”Segment”信息。

數(shù)據(jù)段和BSS段唯一區(qū)別就是:數(shù)據(jù)段從文件中初始化內(nèi)容,而B(niǎo)SS段的內(nèi)容全都初始化為0。

6.4.2 堆和棧

操作系統(tǒng)通過(guò)使用VMA來(lái)對(duì)進(jìn)程的地址空間進(jìn)行管理。進(jìn)程在執(zhí)行的時(shí)候它還需要用到等空間。一個(gè)進(jìn)程中的棧和堆分別對(duì)應(yīng)一個(gè)VMA。
進(jìn)程虛擬地址空間的概念:操作系統(tǒng)通過(guò)給進(jìn)程空間劃分一個(gè)個(gè)VMA來(lái)管理進(jìn)程的虛擬空間;基本原則就是將相同權(quán)限屬性的、有相同映像文件的映射成一個(gè)VMA;一個(gè)進(jìn)程基本上可以分為幾種VMA區(qū)域:

    • 代碼VMA,權(quán)限只讀、可執(zhí)行;有映像文件。
    • 數(shù)據(jù)VMA,權(quán)限可讀寫、可執(zhí)行;有映像文件。
    • 堆VMA,權(quán)限可讀寫、可執(zhí)行;無(wú)映像文件,匿名,可向上擴(kuò)展。
    • 棧VMA,權(quán)限可讀寫、不可執(zhí)行;無(wú)映像文件,匿名,可向下擴(kuò)展。

6.4.3 堆的最大申請(qǐng)數(shù)量

理論上Linum下虛擬地址空間分給進(jìn)程本身的是3GB,win是2GB,但實(shí)際上,Linux分配的程序的最大內(nèi)存是2.9GB,win分配的為1.5GB。
有些操作系統(tǒng)使用了一種叫做隨機(jī)地址空間分布技術(shù),使得進(jìn)程的堆空間變小。

6.4.4 段地址對(duì)齊

可執(zhí)行文件最終是要被操作系統(tǒng)裝載運(yùn)行的,這個(gè)裝載的過(guò)程一般是通過(guò)虛擬內(nèi)存頁(yè)映射機(jī)制完成。在映射過(guò)程中,頁(yè)是映射的最小單位。

6.4.5 進(jìn)程棧初始化

進(jìn)程剛開(kāi)始啟動(dòng)的時(shí)候,須知道一些進(jìn)程運(yùn)行的環(huán)境,最基本的就是系統(tǒng)環(huán)境變量和進(jìn)程的運(yùn)行參數(shù),很常見(jiàn)的一種做法是操作系統(tǒng)在進(jìn)程啟動(dòng)前將這些信息提前保存到進(jìn)程的虛擬空間的棧中。

6.5 Linux內(nèi)核裝載ELF過(guò)程簡(jiǎn)介

首先在用戶層面,bash進(jìn)程會(huì)調(diào)用fork()系統(tǒng)調(diào)用創(chuàng)建一個(gè)新的進(jìn)程,然后新的進(jìn)程調(diào)用execve()系統(tǒng)調(diào)用執(zhí)行指定的ELF文件,原先的bash進(jìn)程繼續(xù)返回等待剛才啟動(dòng)的新進(jìn)程結(jié)束,然后繼續(xù)等待用戶輸入命令。

6.6 Windows PE的裝載

RVA:它表示一個(gè)相對(duì)虛擬地址,相當(dāng)于文件中的偏移量的東西。它是相對(duì)于PE文件的裝載基地址的一個(gè)偏移地址。每個(gè)PE文件在裝載時(shí)都會(huì)有一個(gè)裝載目標(biāo)地址,這個(gè)地址就是基地址
裝載一個(gè)PE可執(zhí)行文件的過(guò)程:

  • 先讀取文件的第一個(gè)頁(yè),這個(gè)頁(yè)包含了DOS頭、PE文件頭、段表
  • 檢查進(jìn)程地址空間中,目標(biāo)地址是否可用,如果不可用,則另外選一個(gè)轉(zhuǎn)載地址
  • 使用段表中提供的信息,將PE文件中所有段一一映射到地址空間中相應(yīng)的位置
  • 如果裝載地址不是目標(biāo)地址,則進(jìn)行Rebasing
  • 裝載所有PE文件所需要的DLL文件
  • 對(duì)PE文件中所有導(dǎo)入符號(hào)進(jìn)行解析
  • 根據(jù)PE頭中指定的參數(shù),建立初始化棧和堆
  • 建立主線程并且啟動(dòng)進(jìn)程

PE文件中,與裝載相關(guān)的主要信息都包含在PE擴(kuò)展頭和段表中。

轉(zhuǎn)載于:https://www.cnblogs.com/Tan-sir/p/7488796.html

總結(jié)

以上是生活随笔為你收集整理的程序员的自我修养六可执行文件的装载与进程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。