可執行文件的裝載與進程一點小總結 《程序員的自我修養》·筆記

可執行文件的裝載與進程小結

  • 進程的虛擬地址空間
    ??每個程序被運行起來之后都擁有自己獨立的虛擬地址空間,這個虛擬地址空間的大小是CPU的位數決定的。比如,32位的硬件平臺決定了虛擬地址空間的地址為(2^32-1),也就是我們常說的4GB虛擬內存的大小。
    ??需要注意的是,分配的4GB的虛擬空間并不是全部給進程的,比如,linux下1GB給操作系統,余下的3GB中基本上都分配給進程,但是3GB中的其中小部分要分配給其他用途;win下面按照2GB、2GB進行類似的劃分。

  • 裝載的方式

    • 裝載的基本思想
      ??將程序最常用的部分駐留在內存。最常用的方法是頁映射,如下。
    • 頁映射
      ??要完成頁映射就要將內存和磁盤中的數據和指令按“頁”為單位劃分成若干頁,以后所有的裝載和操作的單位就是頁。下圖就是可執行文件(虛擬空間)與物理內存的映射(不考慮程序運行的虛擬地址空間):

      ??關于頁的操作有很多種情況,比如“內存滿時的頁置換”、“頁錯誤”等等情況下采取的種種策略(FIFO、LUR)這里不再贅述。
  • 從操作系統的角度看可執行文件的裝載方法

    • 進程的創建
      ??從操作系統的角度看,一個進程最關鍵的特征就是他有獨立的虛擬地址空間,這使得它有別于其他進程,上述的映射關系直接使用物理地址進行操作,那么每次頁裝入的時候就要就行重定位,所以我們需要引入進程的虛擬運行地址空間。那么,下面就說一下從操作系統角度看一個程序被執行的大致過程:
      ??1.首先是創建程序對應的虛擬地址空間。即進行虛擬地址空間與程序執行的物理內存的映射(方向是進程虛擬空間到進程物理內存)。我們知道一個虛擬空間由一組頁映射函數將虛擬空間各個頁映射至相應的物理空間。此處所謂的“創建”并不是創建空間,而是創建虛擬空間到物理內存空間的映射函數所需要的一系列的數據結構,對于Linux就是創建一個“頁目錄”結構即可,并不需要設置虛擬頁到物理頁的映射關系。linux下將虛擬空間的各個頁映射至相應的物理空間,實際上只是分配了一個頁目錄(Page Directory)就可以了,并且不用設置頁映射關系,這些映射關系到后面程序發生頁錯誤的時候再進行設置。
      ??2.讀取可執行文件頭,建立進程虛擬地址空間和可執行文件的映射關系。這一步將可執行文件空間與虛擬空間關聯起來(方向是可執行文件虛擬空間到進程虛擬空間),使得發生缺頁錯誤時,OS能夠知道到可執行文件中的哪個位置去找到所需要加載到物理內存的內容;這種映射關系只是保存在操作系統內部的一個數據結構。Linux中將進程虛擬空間中的一個段叫做虛擬內存區域(VMA,Virtual Memory Area);在Windows中將這個叫做虛擬段(Virtual Section)。
      ??【注意】由于可執行文件在裝載的時候實際上是被映射的虛擬空間,所以可執行文件很多時候被稱作映射文件。進程虛擬地址空間和可執行文件的映射關系如下:

      ??3.設置CPU的指令寄存器為可執行文件的入口地址,啟動運行:OS將控制權交給了進程。從進程的角度看這一步可以簡單的認為操作系統執行了一條跳轉指令,直接跳轉到可執行文件的入口(ELF文件頭中保存了入口地址項)。
    • 頁錯誤
      ??完成上述三個步驟之后,其實OS僅僅只是可執行文件與進程虛存之間建立起了映射——即通常意義上所說的程序加載到了內存,實際上這里說的是程序完全加載到了虛擬內存,但是代碼和數據根本就沒有加載到物理內存中,進程虛存與物理內存空間的映射關系其實也沒有建立起來(上面也說了在“頁錯誤階段進行映射關系的設置”),這樣程序一旦開始執行,將會立即出現缺頁錯誤,即程序將要訪問的進程虛存地址并沒有映射到物理內存空間的某個page(虛擬頁),(頁錯誤的處理線程執行)此時OS會重新接管系統控制權,查詢剛才第二步保存的可執行文件到進程虛存映射關系的數據結構,找到所缺的虛擬頁對應于可執行文件中的偏移,然后在進程物理內存分配一個物理頁,將可執行文件中的內容從磁盤讀入到內存中,并將這個物理頁(進程物理內存)與該虛擬頁(進程虛存)建立起映射,然后OS將控制權重新交給進程,程序繼續執行。如下圖所示:
  • 進程虛存空間分布

    • ELF文件在映射到進程虛存的過程中是以系統的頁作為單位的,那么每個段在映射時的長度都應該是系統頁長度的整數倍;如果不是那么多余部分也將占用一頁。這樣的話內存浪費是大問題。
    • ELF文件中, 段的權限只有為數不多的幾種組合:
      1.以代碼段為代表的權限為可讀可執行的段
      2.以數據段和BSS段為代表的權限為可讀可寫的段
      3.以只讀數據段為代表的權限為只讀的段。
      對于相同權限的段,把它們合并到一起當作一個段進行映射。如下圖,".text"和".init"段都是可讀可執行的,則進行合并,形成一個"segment":


    • 堆和棧
      kernel使用VMA劃分來管理進程的虛擬地址空間。典型的進程包括代碼:
      1.代碼VMA(RE屬性,有映像文件)
      2.數據VMA(RWE屬性,有映像文件)
      3.堆VMA(RWE屬性,無映像文件,向上擴展)
      4.棧VMA(RW屬性,無映像文件,向下擴展)
      如下圖所示:



      【需要注意】其實DATA segment對應的就是DATA VMA;CODE segment對應的就是CODE VMA。幾乎在每一個進程的VMS視圖中都可以看見[heap]和[stack]這兩個VMA,但是這兩個VMA在可執行文件中都沒有對應的segment存在,所以它們被稱之為匿名VMA。malloc()庫函數就是從堆VMA中分配空間。

  • Linux內核裝載ELF過程
    ??Linux環境下,fork系統調用將會創建一個與當前task完全一樣的新task,直到應用程序調用exec*系列的Glibc庫函數最終調用execve()系統調用之后,Linux內核才開始真正裝載ELF可執行文件(映像文件)。execve內核入口為sys_execve(),隨之調用do_execve()將查找這個可執行文件,如果找到則讀取ELF可執行文件的前128個字節,然后調用search_binary_handle()通過ELF文件頭中的e_ident得到可執行文件的Magic Number,判斷出這是一個什么類型的可執行文件,并調用不同可執行文件的裝載處理程序,對于ELF可執行文件而言,其裝載處理程序為load_elf_binary(),這個函數將會把execve系統調用的返回地址修改為ELF可執行文件的入口點,對于靜態鏈接得到的ELF文件即文件頭中定義的e_entry,對于動態鏈接得到的ELF可執行文件則是動態鏈接器。一步一步返回到sys_execve()之后,因為返回地址已經被修改為了ELF程序入口地址了,所以系統調用返回到用戶態之后,EIP指令寄存器將直接跳轉到ELF程序入口地址,程序開始執行,裝載完成。
    ELF文件的裝載過程:

    fork -> execve() -> sys_execve() -> do_execve()

    do_execve() 讀取文件的前128個字節判斷文件的格式(一般根據魔數來判斷,比如elf的頭四個字節為:0x7F, e, l, f)。
    ??然后調用search_binary_handle()去搜索和匹配合適的可執行文件裝載處理過程,對于elf則調用load_elf_binary():

    • 檢查ELF可執行文件格式的有效性
    • 尋找動態鏈接的“.interp”段,設置動態連接器路徑
    • 根據ELF可執行文件的程序頭表的描述,對ELF文件進行映射,比如代碼、數據、只讀數據。
    • 根據ELF進程環境,比如進程啟動是EDX寄存器的地址應該是DT_FINI的地址。
    • 將系統調用的返回地址修改成ELF可執行文件的入口點,這個入口點取決于程序的鏈接方式,靜態ELF可執行文件為e_entry所指的地址,對于動態ELF入口點為動態連接器。

    Load_elf_binary()執行完畢,返回至do_execve()再返回至sys_execve(),最后一步的系統調用返回地址改成了被裝在的ELF程序入口地址。當sys_execve()系統調用從內核態返回到用戶態時,EIP寄存器直接跳轉到了ELF程序的入口地址,新程序開始執行。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容