大作业报告
計算機系統基礎課程報告
計算機科學與技術學院
2022年3月
摘 要
摘要是論文內容的高度概括,應具有獨立性和自含性,即不閱讀論文的全文,就能獲得必要的信息。摘要應包括本論文的目的、主要內容、方法、成果及其理論與實際意義。摘要中不宜使用公式、結構式、圖表和非公知公用的符號與術語,不標注引用文獻編號,同時避免將摘要寫成目錄式的內容介紹。
(摘要0分,缺失-1分,根據內容精彩稱都酌情加分0-1分)
關鍵詞:計算機系統,helloworld,編譯器,操作系統
本文將從hello的誕生開始,通過hello所涉及到的過程對這些過程加以詳細的介紹。通過linux上的gcc調試和課本上的知識對過程中的每一個步驟進行詳細的解釋與分析。并且從中尋找自己尚不了解的部分,及時補充該部分知識。使得自己對于計算機系統和linux有更深一步的理解。分析了從 .c文件轉化為可執行文件過程中的預處理、編譯、匯編和鏈接階段。同時也介紹了可執行文件執行過程中的進程管理、存儲管理和I/O管理的具體實現方法。在linux中,hello.c經過cpp預處理,ccl編譯,as匯編,ld鏈接之后,最終可以作為目標程序執行。在shell中鍵入啟動命令后,shell會使用fork為其創建并生成子進程,這樣hello從Program轉換為Process,這是P2P的過程。
然后shell為其execve映射虛擬內存。進入程序入口后,程序開始加載物理內存,然后進入main函數執行目標代碼。 CPU為正在運行的hello分配時間片以執行邏輯控制流。程序完成后,shell父進程負責恢復hello進程,內核刪除相關的數據結構。以上就是020的過程。
**
目 錄
第1章 概述 - 4 -******
1.1 Hello簡介 - 4 -
1.2 環境與工具 - 4 -
1.3 中間結果 - 4 -
1.4 本章小結 - 4 -
第2章 預處理 - 5 -**
2.1 預處理的概念與作用 - 5 -
2.2在Ubuntu下預處理的命令 - 5 -
2.3 Hello的預處理結果解析 - 5 -
2.4 本章小結 - 5 -
第3章 編譯 - 6 -**
3.1 編譯的概念與作用 - 6 -
3.2 在Ubuntu下編譯的命令 - 6 -
3.3 Hello的編譯結果解析 - 6 -
3.4 本章小結 - 6 -
第4章 匯編 - 7 -**
4.1 匯編的概念與作用 - 7 -
4.2 在Ubuntu下匯編的命令 - 7 -
4.3 可重定位目標elf格式 - 7 -
4.4 Hello.o的結果解析 - 7 -
4.5 本章小結 - 7 -
第5章 鏈接 - 8 -**
5.1 鏈接的概念與作用 - 8 -
5.2 在Ubuntu下鏈接的命令 - 8 -
5.3 可執行目標文件hello的格式 - 8 -
5.4 hello的虛擬地址空間 - 8 -
5.5 鏈接的重定位過程分析 - 8 -
5.6 hello的執行流程 - 8 -
5.7 Hello的動態鏈接分析 - 8 -
5.8 本章小結 - 9 -
第6章 HELLO進程管理 - 10 -**
6.1 進程的概念與作用 - 10 -
6.2 簡述殼Shell-bash的作用與處理流程 - 10 -
6.3 Hello的fork進程創建過程 - 10 -
6.4 Hello的execve過程 - 10 -
6.5 Hello的進程執行 - 10 -
6.6 hello的異常與信號處理 - 10 -
6.7本章小結 - 10 -
第7章 HELLO的存儲管理 - 11 -**
7.1 hello的存儲器地址空間 - 11 -
7.2 Intel邏輯地址到線性地址的變換-段式管理 - 11 -
7.3 Hello的線性地址到物理地址的變換-頁式管理 - 11 -
7.4 TLB與四級頁表支持下的VA到PA的變換 - 11 -
7.5 三級Cache支持下的物理內存訪問 - 11 -
7.6 hello進程fork時的內存映射 - 11 -
7.7 hello進程execve時的內存映射 - 11 -
7.8 缺頁故障與缺頁中斷處理 - 11 -
7.9動態存儲分配管理 - 11 -
7.10本章小結 - 12 -
第8章 HELLO的IO管理 - 13 -**
8.1 Linux的IO設備管理方法 - 13 -
8.2 簡述Unix IO接口及其函數 - 13 -
8.3 printf的實現分析 - 13 -
8.4 getchar的實現分析 - 13 -
8.5本章小結 - 13 -
結論 - 14 -**
附件 - 15 -**
參考文獻 - 16 -**
第1章 概述
1.1 Hello簡介
根據Hello的自白,利用計算機系統的術語,簡述Hello的P2P,020的整個過程。
程序員在編輯器中完成了hello.c的編輯,預處理器根據以#開頭的預處理指令,對hello.c進行預處理。形成hello.i,編譯器將hello.i文件編譯成hello.s,匯編器將hello.s翻譯成機器語言的格式,打包成可重定位目標程序,稱為.o。經過鏈接器鏈接,形成可執行文件hello。
用戶鍵入指令之后,操作系統的shell會folk一個子進程,在子進程中調用execve加載可執行文件hello。然后程序跳轉到start位置,調用main函數,執行完成后hello程序會被shell回收
1.2 環境與工具
列出你為編寫本論文,折騰Hello的整個過程中,使用的軟硬件環境,以及開發與調試工具。
硬件環境:Intel? Core? i5-8300H CPU; 8.00GB RAM
軟件環境:Windows10 64位;Vmware 15.5.0;Ubuntu 19.04 LTS 64位
開發工具:Visual Studio 2017 64位;CodeBlocks 64位;vi/vim/gedit+gcc;GCC;objdump;EDB;readelf;
1.3 中間結果
列出你為編寫本論文,生成的中間結果文件的名字,文件的作用等。
hello.i hello.c預處理之后的文本文件
hello.s hello.i編譯之后的文本文件
hello.o hello.s匯編之后的二進制文件
hello hello.o鏈接之后的二進制文件
hello.asm hello的反匯編文件
helloo.asm hello.o的反匯編文件
hello.elf hello的elf文件信息
helloo.elf hello.o的elf文件信息
1.4 本章小結
本章簡要介紹了hello的p2p o2o的全部進程,以及實驗的環境,軟件,文件等信息
(第1章0.5分)
第2章 預處理
2.1 預處理的概念與作用
預處理一般是指由預處理器對程序源代碼文本進行處理的過程。預處理器(cpp)根據以字符#開頭的命令,修改原始的C程序。結果是得到另一個C程序,通常是以.i作為文件擴展名。
作用:
C語言的預處理主要有三個方面的內容:宏定義、文件包含和條件編譯。
1.宏定義:將宏名替換為文本(字符串或代碼)。
2.文件包含:預處理程序將查找指定的被包含文件,并將其復制插入到#include命令出現的位置上。比如hello.c中第1行的#include命令告訴預處理器讀取系統頭文件stdio.h的內容,并把它直接插人程序文本中。
3.條件編譯:有些語句希望在條件滿足時才編譯,預處理過程中根據條件決定需要編譯的代碼。
2.2在Ubuntu下預處理的命令
圖2-1
應截圖,展示預處理過程!
2.3 Hello的預處理結果解析
圖2-2
這里的3100行之后的內容為原.c文件中的13行之后的內容,之前的內容為3個頭文件被復制并替換到include指令位置產生的。
2.4 本章小結
本章闡述了預處理的相關知識點,并對hello.c進行了預處理,分析了預處理的過程及其結果
(第2章0.5分)
第3章 編譯
3.1 編譯的概念與作用
編譯是編譯器(ccl)將文本文件hello.i翻譯成文本文件hello.s的過程, hello.s包含一個匯編語言程序。
過程:
1.詞法分析 2.語法分析 3.語義分析 4.源代碼優化 5.代碼生成,目標代碼優化。
作用:把代碼翻譯成匯編語言。
注意:這兒的編譯是指從 .i 到 .s 即預處理后的文件到生成匯編語言程序
3.2 在Ubuntu下編譯的命
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mK1XTuma-1653057190900)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.004.png)]圖3-1
應截圖,展示編譯過程!
3.3 Hello的編譯結果解析
3.3.1 數據
1.int sleepsecs:
sleepsecs是一個全局變量,存在.data段中。由于sleepsecs為int類型,賦值時發生了類型的強制轉換。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9eolfgwP-1653057190901)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.005.png)]
圖3-2
2.int i:
i是一個局部變量。局部變量一般存在寄存器或堆棧中。由i的賦值語句可以看出i存放的位置是-4(%rbp)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-imu5vUEY-1653057190901)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.006.png)]圖3-3
3.字符串:
程序中有兩個字符串:“Usage: Hello 學號 姓名!\n"和"Hello %s %s\n”
都存在只讀數據段中。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xnqXKBBK-1653057190901)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.007.png)]圖3-4
4.數組:
程序中有一個數組argv[],argv[[1]]和argv[[2]]作為for循環中printf的參數。
由取argv[[1]]和argv[[2]]值的匯編語句可知argv的首地址是-32(%rbp)。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-494oqjBM-1653057190902)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.008.png)]圖3-5
3.3.2 賦值
1.int sleepsecs=2.5:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hdZm33dA-1653057190902)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.009.png)]sleepsecs是全局變量,在.data節中被賦值。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3ycLpk5d-1653057190903)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.010.png)]圖3-6
2.i=0:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pvK3tnYs-1653057190904)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.011.png)]圖3-7
3.3.3 類型轉換:
將float類型的2.5賦值給int類型的sleepsecs時發生了強制類型轉換。2.5被向下取整為2.
3.3.4 算術操作
主要為 .c文件中的i++,轉換為.s文件為addl $1, -4(%rbp)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-USV5jokI-1653057190904)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.012.png)]圖3-8
3.3.5 關系操作
主要為argc != 3 和 i < 10
argc != 3 編譯成
cmpl $3, -20(%rbp)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-cxMO6NgH-1653057190904)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.013.png)]圖3-9
i < 10 編譯成
cmpl $9, -4(%rbp)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aGAM5H3I-1653057190905)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.014.png)]圖3-10
3.3.6 數組/指針/結構操作
程序中對argv[[1]],argv[[2]]的尋址被編譯為基址+偏移的尋址方式。
-32(%rbp)存放的是argv的首地址,在首地址上+8,+16得到argv[[1]],argv[[2]]的地址。
3.3.7 控制轉移
c文件中有if執行的跳轉和for循環執行的跳轉,在.s文件中,都是通過cmp和jxx指令組合實現的
3.3.8 函數操作
使用call指令調用其他函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WiuBuZvM-1653057190905)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.015.png)]圖3-11
此部分是重點,說明編譯器是怎么處理C語言的各個數據類型以及各類操作的。應分3.3.1~ 3.3.x等按照類型和操作進行分析,只要hello.s中出現的屬于大作業PPT中P4給出的參考C數據與操作,都應解析。
3.4 本章小結
本章介紹了編譯的相關知識,介紹了編譯的過程,并對編譯的結果進行了解析。
(第3章2分)
第4章 匯編
4.1 匯編的概念與作用
匯編器(as)將hello.s翻譯成機器語言指令,把這些指令打包成一種叫做可重定位目標程序的格式,并將結果保存在目標文件hello.o中。
作用:將匯編代碼轉變為機器指令,生成目標文件。
注意:這兒的匯編是指從 .s 到 .o 即編譯后的文件到生成機器語言二進制程序的過程。
4.2 在Ubuntu下匯編的命令
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CPRgeW1r-1653057190905)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.016.png)]圖4-1
應截圖,展示匯編過程!
4.3 可重定位目標elf格式
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vSUHNWfK-1653057190906)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.017.png)]圖4-2
將readelf的結果輸出到文件中
\1. ELF頭:
ELF頭以一個16字節的序列開始,這個序列描述了生成該文件的系統的字的大小和字節順序。ELF頭剩下的部分包含幫助鏈接器語法分析和解釋目標文件的信息,其中包括ELF頭的大小、目標文件的類型、機器類型、節頭部表的文件偏移,節頭部表中條目的大小和數量等。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mVwpCn1y-1653057190906)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.018.png)]圖4-3
2.節頭表
記錄了每個節的名稱、類型、屬性(讀寫權限)、在ELF文件中所占的長度、對齊方式和偏移量
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QC9SMEYV-1653057190907)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.019.png)]圖4-4
3.重定位節
重定位條目告訴鏈接器在將目標文件合并成可執行文件時如何修改這個引用。如圖,偏移量是需要被修改的引用的節偏移,符號標識被修改引用應該指向的符號。類型告知鏈接器如何修改新的引用,加數是一個有符號常數,一些類型的重定位要用它對被修改引用的值做偏移調整。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0HJW1Jbv-1653057190907)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.020.png)]圖4-5
ELF重定位條目:
r_offset:
此成員指定應用重定位操作的位置。不同的目標文件對于此成員的解釋會稍有不同。
r_info:
此成員指定必須對其進行重定位的符號表索引以及要應用的重定位類型。
重定位類型特定于處理器。重定位項的重定位類型或符號表索引是將 ELF32_R_TYPE 或 ELF32_R_SYM 分別應用于項的r_info成員所得的結果。
r_addend:
此成員指定常量加數,用于計算將存儲在可重定位字段中的值。
重定位類型:
R_X86_64_PC3:重定位一個使用32位PC相對地址的引用。在指令中編碼的32位值加上PC的當前運行時值,得到有效地址。
R_X86_64_32:重定位一個使用32位PC絕對地址的引用。直接使用在指令中編碼的32位值作為有效地址。
4.符號表
它存放在程序中定義和引用的函數和全局變量的信息,.symtab符號表不包含局部變量的條目。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-c5aSpUqY-1653057190907)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.021.png)]圖4-6
分析hello.o的ELF格式,用readelf等列出其各節的基本信息,特別是重定位項目分析。
4.4 Hello.o的結果解析
1.反匯編代碼與hello.s差別不大。
\2. hello.s使用十進制,反匯編代碼中使用的是16進制。
3.分支轉移:hello.s中使用段的標號(如:.L3)作為分支后跳轉的地址,反匯編代碼中用相對main函數起始地址的偏移表示跳轉的地址。
4.全局變量:hello.s中使用段名稱+%rip訪問,反匯編代碼中使用0+%rip訪問。機器語言中待訪問的全局變量地址為全0.在重定位節中有對應的重定位條目,鏈接之后確定地址。
5.函數調用:hello.s中函數調用后直接跟著函數的名字,反匯編代碼中函數調用的目標地址是當前的下一條指令。在機器語言中call后的地址為全0.在重定位節中有對應的重定位條目,鏈接之后確定地址。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-65hqsDKB-1653057190908)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.022.png)]圖4-7
objdump -d -r hello.o 分析hello.o的反匯編,并請與第3章的 hello.s進行對照分析。
說明機器語言的構成,與匯編語言的映射關系。特別是機器語言中的操作數與匯編語言不一致,特別是分支轉移函數調用等。
4.5 本章小結
這章介紹了匯編的知識。分析了可重定位目標文件的格式,比較了反匯編代碼與hello.s的相同點與不同點。
(第4章1分)
第5章 鏈接
5.1 鏈接的概念與作用
鏈接是將各種代碼和數據片段收集并組合成為一個單一文件的過程。
作用:將函數庫中相應的代碼組合到目標文件中。
注意:這兒的鏈接是指從 hello.o 到hello生成過程。
5.2 在Ubuntu下鏈接的命令
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1uHJMnZa-1653057190908)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.023.png)]圖5-1
使用ld的鏈接命令,應截圖,展示匯編過程! 注意不只連接hello.o文件
5.3 可執行目標文件hello的格式
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Rr4TsX0n-1653057190908)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.024.png)]
1.節頭表:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-deXIfjIM-1653057190908)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.025.png)]圖5-2
.text節是保存了程序代碼指令的代碼節。一段可執行程序,存在Phdr,.text就會存在于text段中。由于.text節保存了程序代碼,因此節的類型為SHT_PROGBITS。
.rodata 保存只讀數據。類型SHT_PROGBITS。
.plt 過程鏈接表(Procedure Linkage Table),包含動態鏈接器調用從共享庫導入的函數所必須的相關代碼。存在于text段中,類型SHT_PROGBITS。
.bss節保存未初始化全局數據,是data的一部分。程序加載時數據被初始化成0,在程序執行期間可以賦值,未保存實際數據,類型SHT_NOBITS。
.got節保存全局偏移表。它和.plt節一起提供了對導入的共享庫函數訪問的入口。由動態鏈接器在運行時進行修改。如果攻擊者獲得堆或者.bss漏洞的一個指針大小寫原語,就可以對該節任意修改。類型SHT_PROGBITS。
.dynsym節保存共享庫導入的動態符號信息,該節在text段中,類型SHT_DYNSYM。
.dynstr保存動態符號字符串表,存放一系列字符串,代表了符號的名稱,以空字符作為終止符。
.rel節保存重定位信息,類型SHT_REL。
.hash節,也稱為.gnu.hash,保存一個查找符號散列表。
.symtab節,保存了ElfN_Sym類型的符號信息,類型SHT_SYMTAB。
strtab節,保存符號字符串表,表中內容被.symtab的ElfN_Sym結構中的st_name條目引用。類型SHT_SYMTAB。
.shstrtab節,保存節頭字符串表,以空字符終止的字符串集合,保存了每個節節名,如.text,.data等。有個e_shsrndx的ELF文件頭條目會指向.shstrtab節,e_shstrndx中保存了.shstrtab的偏移量。這節的類型是SHT_SYMTAB。
.ctors和.dtors節,前者構造器,后者析構器,指向構造函數和析構函數的函數指針,構造函數是在main函數執行前需要執行的代碼,析構是main函數之后需要執行的代碼。
2.程序頭表
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ojnkGGYe-1653057190909)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.026.png)]圖5-3
可以看出,程序包含八個段。
1.PTDR: 指定程序頭表在文件及程序內存映像中的位置和大小。
2.INTERP: 指定要作為解釋程序調用的以空字符結尾的路徑名的位置和大小。對于動態可執行文件,必須設置此類型。
3.LOAD: 指定可裝入段,通過p_filesz和p_memsz進行描述。文件中的字節會映射到內存段的起始位置。
4.DYNAMIC: 指定動態鏈接信息。
5.NOTE: 指定輔助信息的位置和大小。
6.GNU_STACK: 權限標志,標志棧是否是可執行的。
7.GNU_RELRO: 指定在重定位結束之后那些內存區域是需要設置只讀。
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
5.4 hello的虛擬地址空間
使用edb加載hello,查看本進程的虛擬地址空間各段信息,并與5.3對照分析說明。
虛擬地址空間各段信息:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-k9Y6EaKY-1653057190909)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.027.png)]圖5-4
(1).PDHR:起始位置為0x400040,大小為0x1c0
(2).INTERP:起始位置為0x400200,大小為0x1c
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-EFe0KnL8-1653057190909)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.028.png)]圖5-5
(3).LOAD:起始位置為0x400000,大小為0x81c
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QgSnebJ2-1653057190910)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.029.png)]圖5-6
(4). 在symbol處查找5.3相應的節就可以在Data Dump里找相應的節然后右邊就是相應的二進制形式
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1KX7x1Ns-1653057190910)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.030.png)]圖5-7
5.5 鏈接的重定位過程分析
1.hello中增加了許多節和被調用的函數。
2.對rodata的引用:在hello.o的反匯編文件中對printf參數字符串的引用使用全0替代。在hello中則使用確定地址,這是因為鏈接后全局變量的地址能夠確定。
3.hello.o中main 的地址從0開始,hello中main的地址不再是0.庫函數的代碼都鏈接到了程序中。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RnXvFlog-1653057190911)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.031.png)]
圖5-8
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3OuqOglB-1653057190911)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.032.png)]
圖5-9
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kKtmdbWY-1653057190911)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.033.png)]
圖5-10
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-GAfYJoaU-1653057190912)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.034.png)]
圖5-11
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iRpeM6YR-1653057190912)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.035.png)]
圖5-12
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-bSW24WfG-1653057190912)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.036.png)]
圖5-13
上面的五張圖就是我們hello反匯編的結果。
我們可以看出前面的編號有明顯的不同。因為是放在了虛擬內存的相應的位置0X400000相的位置。而hello.o反匯編是從0開始的
.o反匯編就直接是.text然后main函數如下圖
objdump -d -r hello 分析hello與hello.o的不同,說明鏈接的過程。
結合hello.o的重定位項目,分析hello中對其怎么重定位的。
5.6 hello的執行流程
程序名稱 程序地址
ld-2.29.so!_dl_start 0x7f7f62a7d093
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ERVZFmA3-1653057190913)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.037.png)]
圖5-11
載入:[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gMYMyEKC-1653057190913)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.038.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sLUOwKSq-1653057190913)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.039.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-j7JSUo42-1653057190913)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.040.png)]
_dl_start
_dl_init
開始執行
_start
_libc_start_main
_init
執行main:
_main
_printf
_exit
_sleep
_getcha
_dl_runtime_resolve_xsave
_dl_fixup
_dl_lookup_symbol_x
退出:
exit
使用edb執行hello,說明從加載hello到_start,到call main,以及程序終止的所有過程。請列出其調用與跳轉的各個子程序名或程序地址。
5.7 Hello的動態鏈接分析
程序調用一個由共享庫定義的函數時,編譯器沒有辦法預測這個函數的運行時地址,因為定義它的共享模塊在運行時可以加載到任意位置。GNU編譯系統使用延遲綁定的技術解決這個問題,將過程地址的延遲綁定推遲到第一次調用該過程時。
延遲綁定要用到全局偏移量表(GOT)和過程鏈接表(PLT)兩個數據結構。如果一個目標模塊調用定義在共享庫中的任何函數,那么它就有自己的GOT和PLT。
PLT:PLT是一個數組,其中每個條目是16字節代碼。PLT[0]是一個特殊條目,跳轉到動態鏈接器中。每個條目都負責調用一個具體的函數。PLT[[1]]調用系統啟動函數 (__libc_start_main)。從PLT[[2]]開始的條目調用用戶代碼調用的函數。
GOT:GOT是一個數組,其中每個條目是8字節地址。和PLT聯合使用時,GOT[0]和GOT[[1]]包含動態鏈接器在解析函數地址時會使用的信息。GOT[[2]]是動態鏈接器在ld-linux.so模塊中的入口點。其余的每個條目對應于一個被調用的函數,其地址需要在運行時被解析。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-44KGy6fQ-1653057190914)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.041.png)]圖5-15
在節頭表中找到GOT的起始位置為601000
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MGEAGKqo-1653057190914)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.042.png)]
圖5-16
調用_dl_start之前可以看出有16個為0的字節
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pL7elfSR-1653057190914)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.043.png)]
圖5-17
調用_dl_start之后發現這些值發生了變化
分析hello程序的動態鏈接項目,通過edb調試,分析在dl_init前后,這些項目的內容變化。要截圖標識說明。
5.8 本章小結
本章介紹了鏈接的概念,分析了hello的格式,虛擬地址空間,重定位過程、執行流程和動態鏈接分析。
(第5章1分)
第6章 hello進程管理
6.1 進程的概念與作用
概念:進程是一個執行中程序的實例。是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。
作用:進程的概念為我們提供這樣一種假象,就好像我們的程序是系統中當前運行的唯一程序一樣,我們的程序好像是獨占地使用處理器和內存,處理器好像是無間斷地一條接一條地執行我們程序中的指令,我們程序中的代碼和數據好像是系統內存中唯一的對象。
6.2 簡述殼Shell-bash的作用與處理流程
Shell俗稱殼,是指“為使用者提供操作界面”的軟件(命令解析器)。它接收用戶命令,然后調用相應的應用程序。
1.功能:命令解釋。Linux系統中的所有可執行文件都可以作為Shell命令來執行。
2.處理流程:
1)當用戶提交了一個命令后,Shell首先判斷它是否為內置命令,如果是就通過Shell內部的解釋器將其解釋為系統功能調用并轉交給內核執行。
2)若是外部命令或應用程序就試圖在硬盤中查找該命令并將其調入內存,再將其解釋為系統功能調用并轉交給內核執行。
6.3 Hello的fork進程創建過程
在終端中輸入./hello 學號 姓名,shell判斷它不是內置命令,于是會加載并運行當前目錄下的可執行文件hello.此時shell通過fork創建一個新的子進程。新創建的子進程幾乎但不完全與父進程相同。子進程得到與父進程用戶級虛擬地址空間相同的(但是獨立的)一份副本,包括代碼和數據段、堆、共享庫和用戶棧。子進程還獲得與父進程任何打開文件描述符相同的副本,這就意味著當父進程調用fork時,子進程可以讀寫父進程中打開的任何文件。子進程與父進程有不同的pid。fork被調用一次,返回兩次。在父進程中fork返回子進程的pid,在子進程中fork返回0.父進程與子進程是并發運行的獨立進程。
6.4 Hello的execve過程
execve函數在新創建的子進程的上下文中加載并運行hello程序。execve函數加載并運行可執行目標文件filename,且帶參數列表argv和環境變量列表envp。只有發生錯誤時execve才會返回到調用程序。所以,execve調用一次且從不返回。
加載并運行hello需要以下幾個步驟:
1.刪除已存在的用戶區域。刪除當前進程虛擬地址的用戶部分中已存在的區域結構。
2.映射私有區域。為新程序的代碼、數據、bss和棧區域創建新的區域結構。所有這些新的區域都是私有的、寫時復制的。代碼和數據區被映射為hello文件中的.text和.data區。bss區域是請求二進制零的,映射到匿名文件,其大小包含在hello中。棧和堆區域也是請求二進制零的,初始長度為零。
3.映射共享區域。如果hello程序與共享對象鏈接,那么這些對象都是動態鏈接到這個程序的,然后再映射到用戶虛擬地址空間中的共享區域內。
4.設置程序計數器。設置當前進程上下文中的程序計數器,使之指向代碼區域的入口點。下一次調度這個進程時,它將從這個入口點開始執行。
6.5 Hello的進程執行
系統中的每個程序都運行在某個進程的上下文中。上下文是由程序正確運行所需的狀態組成的。這個狀態包括存放在內存中的程序的代碼和數據,它的棧、通用目的寄存器的內容、程序計數器、環境變量以及打開文件描述符的集合。
一個進程執行它的控制流的一部分的每一時間段叫做時間片。
處理器通常用某個控制寄存器的一個模式位來提供用戶模式和內核模式的功能。設置了模式位時,進程就運行在內核模式中,該進程可以執行指令集中的任何指令,可以訪問系統中的任何內存位置。沒有設置模式位時,進程就運行在用戶模式中,用戶模式中的進程不允許執行特權指令。
在進程執行的某些時刻,內核可以決定搶占當前進程,并重新開始一個先前被搶占了的進程的決定叫做調度。
程序在執行sleep函數時,sleep系統調用顯式地請求讓調用進程休眠,調度器搶占當前進程,并使用一種稱為上下文切換的機制來將控制轉移到新的進程。sleep的倒計時結束后,控制會回到hello進程中。程序調用getchar()時,內核可以執行上下文切換,將控制轉移到其他進程。getchar()的數據傳輸結束之后,引發一個中斷信號,控制回到hello進程中。
6.6 hello的異常與信號處理
異常內容:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OYh4QY0m-1653057190915)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.044.png “???6-3 ??????????±????”)]
圖6-1
信號種類:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XSUVw9Fj-1653057190915)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.045.png “???6-4 ?????·”)]
圖6-2
hello執行過程中會出現哪幾類異常,會產生哪些信號,又怎么處理的。
程序運行過程中可以按鍵盤,如不停亂按,包括回車,Ctrl-Z,Ctrl-C等,Ctrl-z后可以運行ps jobs pstree fg kill 等命令,請分別給出各命令及運行結截屏,說明異常與信號的處理。
6.6.1 亂按與回車
如果亂按過程中沒有回車,這個時候只是把輸入屏幕的字符串緩存起來,如果輸入最后是回車,getchar把回車讀入,并把回車前的字符串當作shell輸入的命令
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xxCHHXRO-1653057190915)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.046.png)]
6.6.2Ctrl+C
如下圖,如果在程序運行過程中輸入Ctrl+C,會讓內核發送一個SIGINT信號給到前臺進程組中的每個進程,結果是終止前臺進程,通過ps命令發現這時hello進程已經被回收。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pyqFd1n8-1653057190916)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.047.png)]
6.6.3 Ctrl+Z
如下圖,如果輸入Ctrl+Z會發送一個SIGTSTP信號給前臺進程組的每個進程,,結果是停止前臺作業,即我們的hello程序
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-szUzqotT-1653057190916)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.048.png)]
6.6.4 fg命令
fg 1 的意思是使第一個后臺作業變為前臺,第一個后臺作業是我們的hello,所以輸入fg 1 后hello程序又開始運行,并且是繼續剛才的進程,輸出剩下的7個字符串。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-U1ivMmwu-1653057190916)(Aspose.Words.5aa29055-1a63-4824-b41e-75128e179b82.049.png)]
6.7本章小結
本章闡述了進程的定義和作用,shell的作用和處理流程,執行hello時的fork和execve過程。分析了hello的進程執行和異常與信號處理過程。
(第6章1分)
第7章 hello的存儲管理
7.1 hello的存儲器地址空間
邏輯地址:在有地址變換功能的計算機中,訪內指令給出的地址 (操作數) 叫邏輯地址,也叫相對地址。要經過尋址方式的計算或變換才得到內存儲器中的實際有效地址,即物理地址。是hello.o中的相對偏移地址。
線性地址:線性地址(Linear Address)是邏輯地址到物理地址變換之間的中間層。在分段部件中邏輯地址是段中的偏移地址,然后加上基地址就是線性地址。
虛擬地址:程序訪問存儲器所使用的邏輯地址稱為虛擬地址。是hello里的虛擬內存地址。
物理地址:在存儲器里以字節為單位存儲信息,為正確地存放或取得信息,每一個字節單元給以一個唯一的存儲器地址,稱為物理地址。是hello里虛擬內存地址對應的物理地址。
結合hello說明邏輯地址、線性地址、虛擬地址、物理地址的概念。
7.2 Intel邏輯地址到線性地址的變換-段式管理
1.基本原理:
在段式存儲管理中,將程序的地址空間劃分為若干個段(segment),這樣每個進程有一個二維的地址空間。在段式存儲管理系統中,為每個段分配一個連續的分區,而進程中的各個段可以不連續地存放在內存的不同分區中。程序加載時,操作系統為所有段分配其所需內存,這些段不必連續,物理內存的管理采用動態分區的管理方法。
在為某個段分配物理內存時,可以采用首先適配法、下次適配法、最佳適配法等方法。
在回收某個段所占用的空間時,要注意將收回的空間與其相鄰的空間合并。
段式存儲管理也需要硬件支持,實現邏輯地址到物理地址的映射。
程序通過分段劃分為多個模塊,如代碼段、數據段、共享段:
–可以分別編寫和編譯
–可以針對不同類型的段采取不同的保護
–可以按段為單位來進行共享,包括通過動態鏈接進行代碼共享
這樣做的優點是:可以分別編寫和編譯源程序的一個文件,并且可以針對不同類型的段采取不同的保護,也可以按段為單位來進行共享。
總的來說,段式存儲管理的優點是:沒有內碎片,外碎片可以通過內存緊縮來消除;便于實現內存共享。缺點與頁式存儲管理的缺點相同,進程必須全部裝入內存。
2.段式管理的數據結構:
為了實現段式管理,操作系統需要如下的數據結構來實現進程的地址空間到物理內存空間的映射,并跟蹤物理內存的使用情況,以便在裝入新的段的時候,合理地分配內存空間。
·進程段表:描述組成進程地址空間的各段,可以是指向系統段表中表項的索引。每段有段基址(baseaddress),即段內地址。
3.段式管理的地址變換
在段式 管理系統中,整個進程的地址空間是二維的,即其邏輯地址由段號和段內地址兩部分組成。為了完成進程邏輯地址到物理地址的映射,處理器會查找內存中的段表,由段號得到段的首地址,加上段內地址,得到實際的物理地址。這個過程也是由處理器的硬件直接完成的,操作系統只需在進程切換時,將進程段表的首地址裝入處理器的特定寄存器當中。這個寄存器一般被稱作段表地址寄存器。
7.3 Hello的線性地址到物理地址的變換-頁式管理
1.基本原理
將程序的邏輯地址空間劃分為固定大小的頁(page),而物理內存劃分為同樣大小的頁框(page frame)。程序加載時,可將任意一頁放入內存中任意一個頁框,這些頁框不必連續,從而實現了離散分配。該方法需要CPU的硬件支持,來實現邏輯地址和物理地址之間的映射。在頁式存儲管理方式中地址結構由兩部構成,前一部分是虛擬頁號(VPN),后一部分為虛擬頁偏移量(VPO):
頁式管理方式的優點是:
1)沒有外碎片
2)一個程序不必連續存放。
3)便于改變程序占用空間的大小(主要指隨著程序運行,動態生成的數據增多,所要求的地址空間相應增長)。
缺點是:要求程序全部裝入內存,沒有足夠的內存,程序就不能執行。
2.頁式管理的數據結構
在頁式系統中進程建立時,操作系統為進程中所有的頁分配頁框。當進程撤銷時收回所有分配給它的頁框。在程序的運行期間,如果允許進程動態地申請空間,操作系統還要為進程申請的空間分配物理頁框。操作系統為了完成這些功能,必須記錄系統內存中實際的頁框使用情況。操作系統還要在進程切換時,正確地切換兩個不同的進程地址空間到物理內存空間的映射。這就要求操作系統要記錄每個進程頁表的相關信息。為了完成上述的功能,—個頁式系統中,一般要采用如下的數據結構。
頁表:頁表將虛擬內存映射到物理頁。每次地址翻譯硬件將一個虛擬地址轉換為物理地址時,都會讀取頁表。頁表是一個頁表條目(PTE)的數組。虛擬地址空間的每個頁在頁表中一個固定偏移量處都有一個PTE。假設每個PTE是由一個有效位和一個n位地址字段組成的。有效位表明了該虛擬頁當前是否被緩存在DRAM中。如果設置了有效位,那么地址字段就表示DRAM中相應的物理頁的起始位置,這個物理頁中緩存了該虛擬頁。如果沒有設置有效位,那么一個空地址表示這個虛擬頁還未被分配。否則,這個地址就指向該虛擬頁在磁盤上的起始位置。
3.頁式管理地址變換
MMU利用VPN來選擇適當的PTE,將列表條目中PPN和虛擬地址中的VPO串聯起來,就得到相應的物理地址。
7.4 TLB與四級頁表支持下的VA到PA的變換
虛擬地址被劃分成4個VPN和1個VPO。每個VPNi都是一個到第i級頁表的索引,其中1<=i<=4.第j級頁表中的每個PTE,1<=j<=3,都指向第j+1級的某個頁表的基址。第四級頁表中的每個PTE包含某個物理頁面的PPN,或者一個磁盤塊的地址。為了構造物理地址,在能夠確定PPN之前,MMU必須訪問4個PTE。將得到的PPN和虛擬地址中的VPO串聯起來,就得到相應的物理地址。
7.5 三級Cache支持下的物理內存訪問
L1 d-cache的結構如圖所示:通過6-11位的組索引找到對應的組,將組中每一行的tag與CT比較,若標記位匹配且有效位為1,說明命中,根據0-5位的塊偏移取出數據,如果沒有匹配成功,則向下一級緩存中查找數據。取回數據后,如果有空閑塊則放置在空閑塊中,否則根據替換策略選擇犧牲塊。
7.6 hello進程fork時的內存映射
當fork函數被當前進程調用時,內核為新進程創建各種數據結構,并分配給它一個唯一的pid。為了給這個新進程創建虛擬內存。它創建了當前進程的mm_struct、區域結構和頁表的原樣副本。它將兩個進程中的每個頁面都標記位只讀,并將兩個進程中的每個區域結構都標記為私有的寫時復制。
當fork在新進程中返回時,新進程現在的虛擬內存剛好和調用fork時存在的虛擬內存相同。當這兩個進程中的任一個后來進行寫操作時,寫時復制機制就會創建新頁面。
7.7 hello進程execve時的內存映射
加載并運行hello需要以下幾個步驟:
1.刪除已存在的用戶區域。刪除當前進程虛擬地址的用戶部分中已存在的區域結構。
2.映射私有區域。為新程序的代碼、數據、bss和棧區域創建新的區域結構。所有這些新的區域都是私有的、寫時復制的。代碼和數據區被映射為hello文件中的.text和.data區。bss區域是請求二進制零的,映射到匿名文件,其大小包含在hello中。棧和堆區域也是請求二進制零的,初始長度為零。
3.映射共享區域。如果hello程序與共享對象鏈接,那么這些對象都是動態鏈接到這個程序的,然后再映射到用戶虛擬地址空間中的共享區域內。
4.設置程序計數器。設置當前進程上下文中的程序計數器,使之指向代碼區域的入口點。下一次調度這個進程時,它將從這個入口點開始執行。
7.8 缺頁故障與缺頁中斷處理
在虛擬內存的習慣說法中,DRAM緩存不命中稱為缺頁。例如:CPU引用了VP3中的一個字,VP3并未緩存在DRAM中。地址翻譯硬件從內存中讀取PTE3,從有效位推斷出VP3未被緩存,并且觸發一個缺頁異常。缺頁異常調用內核中的缺頁異常處理程序,該程序會選擇一個犧牲頁,在此例中就是存放在PP3中的VP4。如果VP4已經被修改了,那么內核就會將它復制回磁盤。無論哪種情況,內核都會修改VP4的頁表條目,反映出VP4不再緩存在主存中這一事實。缺頁之前:
接下來,內核從磁盤復制VP3到內存中的PP3,更新PTE3,隨后返回。當異常處理程序返回時,它會重新啟動導致缺頁的指令,該指令會把導致缺頁的虛擬地址重發送到地址翻譯硬件。但是現在VP3已經緩存在主存中了,那么也命中也能由地址翻譯硬件正常處理了。缺頁之后:
7.9動態存儲分配管理
動態內存分配器維護著一個進程的虛擬內存區域,稱為堆。分配器將堆視為一組不同大小的塊的集合來維護。每個塊就是一個連續的虛擬內存片,要么是已分配的,要么是空閑的。已分配的塊顯式地保留為供應用程序使用??臻e塊可用來分配??臻e塊保持空閑,直到它顯式地被應用所分配。一個已分配的塊保持已分配狀態,直到它被釋放,這種釋放要么是應用程序顯式執行的,要么是內存分配器自身隱式執行的。
1.隱式空閑鏈表:
空閑塊通過頭部中的大小字段隱含地連接著。分配器可以通過遍歷堆中所有的塊,從而間接地遍歷整個空閑塊的集合。
(1)放置策略:首次適配、下一次適配、最佳適配。
首次適配從頭開始搜索空閑鏈表,選擇第一個合適的空閑塊。下一次適配從上一次查詢結束的地方開始。最佳適配檢查每個空閑塊,選擇適合所需請求大小的最小空閑塊。
(2)合并策略:立即合并、推遲合并。
立即合并就是在每次一個塊被釋放時,就合并所有的相鄰塊;推遲合并就是等到某個稍晚的時候再合并空閑塊。
帶邊界標記的合并:
在每個塊的結尾添加一個腳部,分配器就可以通過檢查它的腳部,判斷前面一個塊的起始位置和狀態,從而使得對前面塊的合并能夠在常數時間之內進行。
2.顯式空閑鏈表
每個空閑塊中,都包含一個pred(前驅)和succ(后繼)指針。使用雙向鏈表使首次適配的時間減少到空閑塊數量的線性時間。
空閑鏈表中塊的排序策略:一種是用后進先出的順序維護鏈表,將新釋放的塊放置在鏈表的開始處,另一種方法是按照地址順序來維護鏈表,鏈表中每個塊的地址都小于它后繼的地址。
分離存儲:維護多個空閑鏈表,每個鏈表中的塊有大致相等的大小。將所有可能的塊大小分成一些等價類,也叫做大小類。
分離存儲的方法:簡單分離存儲和分離適配。
7.10本章小結
本章討論了存儲器地址空間,段式管理、頁式管理,TLB與四級頁表支持下的VA到PA的變換,三級Cache支持下的物理內存訪問,hello進程fork時和execve時的內存映射,缺頁故障與缺頁中斷處理和動態存儲分配管理。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO設備管理方法
所有的I/O設備(例如網絡、磁盤和終端)都被模型化為文件,而所有的輸入和輸出都被當做對相應文件的讀和寫來執行。這種將設備優雅地映射為文件的方式,允許Linux內核引出一個簡單、低級的應用接口,稱為Unix I/O,這使得所有的輸入和輸出都能以一種統一且一致的方式來執行。
8.2 簡述Unix IO接口及其函數
I/O接口操作
1.打開文件:一個應用程序通過要求內核打開相應的文件,來宣告它想要訪問一個I/O設備。內核返回一個小的非負整數,叫做描述符,它在后續對此文件的所有操作中標識這個文件。內核記錄有關這個打開文件的所有信息。應用程序只需記住這個描述符。
2.Linux shell創建的每個進程開始時都有三個打開的文件:標準輸入、標準輸出和標準錯誤。
3.改變當前的文件位置:對于每個打開的文件,內核保持著一個文件位置k,初始為0.這個文件位置是從文件開頭起始的字節偏移量。應用程序能夠通過執行seek操作,顯式地設置文件的當前位置為k。
4.讀寫文件:一個讀操作就是從文件復制n>0個字節到內存,從當前文件位置k開始,然后將k增加到k+n。給定一個大小為m字節的文件,當k>=m時執行讀操作會觸發一個稱為end-of-file(EOF)的條件,應用程序能檢測到這個條件。在文件結尾處并沒有明確的“EOF符號”。
類似地,寫操作就是從內存復制n>0個字節到一個文件,從當前文件位置k開始,然后更新k。
5.關閉文件:當應用完成了對文件的訪問之后,它就通知內核關閉這個文件。作為響應,內核釋放文件打開時創建的數據結構,并將這個描述符恢復到可用的描述符池中。無論一個進程因為何種原因終止時,內核都會關閉所有打開的文件并釋放它們的內存資源。
函數:
1.int open(char *filename, int flags, mode_t mode)
進程通過調用open函數來打開一個已存在的文件或者創建一個新文件。open函數將filename轉換為一個文件描述符,而且返回描述符數字。flags參數指明了進程打算如何訪問這個文件。mode參數指定了新文件的訪問權限位。
2.int close(int fd)
進程通過調用close函數關閉一個打開的文件。
3.ssize_t read(int fd, void *buf, size_t n)
應用程序通過調用read函數來執行輸入。read函數從描述符為fd的當前文件位置復制最多n個字節到內存位置buf。返回值-1表示一個錯誤,返回值0表示EOF。否則返回值表示的是實際傳送的字節數量。
4.ssize_t write(int fd, const void *buf, size_t n)
應用程序通過調用write函數來執行輸出。write函數從內存位置buf復制至多n個字節到描述符fd的當前文件位置。
8.3 printf的實現分析
printf的代碼中va_list是一個字符指針,arg表示函數的第二個參數。
vsprintf的作用是格式化。它接受確定輸出格式的格式字符串fnt。用格式字符串對個數變化的參數進行格式化,產生格式化輸出,并返回要打印的字符串的長度。
write的代碼中,先給寄存器傳了幾個參數,然后通過系統調用sys_call,syscall將字符串中的字節從寄存器中通過總線復制到顯卡的顯存中,顯存中存儲的是字符的ASCII碼。字符顯示驅動子程序:從ASCII到字模庫到顯示vram(存儲每一個點的RGB顏色信息)。顯示芯片按照刷新頻率逐行讀取vram,并通過信號線向液晶顯示器傳輸每一個點(RGB分量)
8.4 getchar的實現分析
getchar函數調用read函數,將整個緩沖區都讀到buf里,并將緩沖區的長度賦值給n。返回時返回buf的第一個元素,除非n<0。
異步異常-鍵盤中斷的處理:鍵盤中斷處理子程序。接受按鍵掃描碼轉成ascii碼,保存到系統的鍵盤緩沖區。
getchar等調用read系統函數,通過系統調用讀取按鍵ascii碼,直到接受到回車鍵才返回。
8.5本章小結
本章簡述了Linux的I/O設備管理機制,Unix I/O接口及函數,并簡要分析了printf函數和getchar函數的實現。
(第8章1分)
用計算機系統的語言,逐條總結hello所經歷的過程。
你對計算機系統的設計與實現的深切感悟,你的創新理念,如新的設計與實現方法。
結論:
Hello程序在計算機中從出生到死亡整個過程:
1 寫程序:寫下我們hello程序的代碼
\2. 預處理:對帶#的指令解析,生成hello.i文件
\3. 編譯:把我們的C語言程序編譯成匯編語言程序,生成.s文件
\4. 匯編:把匯編語言轉換成機器代碼,生成重定位信息,生成.o文件。
\5. 鏈接:與動態庫鏈接,生成可執行文件hello
\6. 創建進程:在shell利用./hello運行hello程序,父進程通過fork函數為hello創建進程
\7. 加載程序:通過加載器,調用execve函數,刪除原來的進程內容,加載我們現在進程的代碼,數據等到進程自己的虛擬內存空間。
\8. 執行指令:CPU取指令,順序執行進程的邏輯控制流。這里CPU會給出一個虛擬地址,通過MMU從頁表里得到物理地址, 在通過這個物理地址去cache或者內存里得到我們想要的信息
\9. 異常(信號):程序執行過程中,如果從鍵盤輸入Ctrl-C等命令,會給進程發送一個信號,然后通過信號處理函數對信號進行處理。
\10. 結束:程序執行結束后,父進程回收子進程,內核刪除為這個進程創建的所有數據結構。
到此,我們對hello程序的分析已經全部結束。其實一直以來,我都想要知道一個程序在計算機內部到底是怎么執行的,我們現在有了各種各樣的IDE,我們只需要寫好代碼,按一下build鍵,然后我們的程序就編譯好輸出了,當這中間的所有過程,我們都一點也不清楚,如果以后是在這些過程中發生了錯誤,那么我們會不知所措,這次大作業算是初步了解整個過程,也算是對一個程序的執行有了大體的認識,當還有許許多多的地方,只能算是一筆帶過,實現上的細節還遠遠不清楚,還需要以后的學習中繼續努力。
做大作業的過程相當于對整個學期的知識的復習總結體會升華,對本書的csapp的題目有了更深刻的感受。本書正是對從一個程序員完成一個程序涉及到的方方面面的cs知識的介紹。使我對計算機系統的細節有了更深入的理解感受和興趣。希望未來能更多深入計算機的原理,不只停留在表面上。
(結論0分,缺失 -1分,根據內容酌情加分)
附件
列出所有的中間產物的文件名,并予以說明起作用。
(附件0分,缺失 -1分)
參考文獻
為完成本次大作業你翻閱的書籍與網站等
為完成本次大作業你翻閱的書籍與網站等
[1] Linux GCC 常用命令
https://www.cnblogs.com/ggjucheng/archive/2011/12/14/2287738.html
[2] ELF中與動態鏈接相關的段
https://blog.csdn.net/virtual_func/article/details/48792087
[3] linux bash總結
http://www.cnblogs.com/skywang12345/archive/2013/05/30/3106570.html.
[4] x86在邏輯地址,線性地址,理解虛擬地址和物理地址
https://www.cnblogs.com/bhlsheji/p/4868964.html
[5] printf函數實現的深入剖析
https://www.cnblogs.com/pianist/p/3315801.html
[6] 鍵盤的中斷處理
https://blog.csdn.net/xumingjie1658/article/details/6965176
[7]聊聊Linux動態鏈接中的PLT和GOT(3)——公共GOT表項
https://blog.csdn.net/linyt/article/details/51637832
[8] 深入理解計算機系統(第三版) Randal E.Bryant David R.O’Hallaron!
(參考文獻0分,缺失 -1分)
- 16 -
,這次大作業算是初步了解整個過程,也算是對一個程序的執行有了大體的認識,當還有許許多多的地方,只能算是一筆帶過,實現上的細節還遠遠不清楚,還需要以后的學習中繼續努力。
做大作業的過程相當于對整個學期的知識的復習總結體會升華,對本書的csapp的題目有了更深刻的感受。本書正是對從一個程序員完成一個程序涉及到的方方面面的cs知識的介紹。使我對計算機系統的細節有了更深入的理解感受和興趣。希望未來能更多深入計算機的原理,不只停留在表面上。
(結論0分,缺失 -1分,根據內容酌情加分)
附件
列出所有的中間產物的文件名,并予以說明起作用。
(附件0分,缺失 -1分)
參考文獻
為完成本次大作業你翻閱的書籍與網站等
為完成本次大作業你翻閱的書籍與網站等
[1] Linux GCC 常用命令
https://www.cnblogs.com/ggjucheng/archive/2011/12/14/2287738.html
[2] ELF中與動態鏈接相關的段
https://blog.csdn.net/virtual_func/article/details/48792087
[3] linux bash總結
http://www.cnblogs.com/skywang12345/archive/2013/05/30/3106570.html.
[4] x86在邏輯地址,線性地址,理解虛擬地址和物理地址
https://www.cnblogs.com/bhlsheji/p/4868964.html
[5] printf函數實現的深入剖析
https://www.cnblogs.com/pianist/p/3315801.html
[6] 鍵盤的中斷處理
https://blog.csdn.net/xumingjie1658/article/details/6965176
[7]聊聊Linux動態鏈接中的PLT和GOT(3)——公共GOT表項
https://blog.csdn.net/linyt/article/details/51637832
[8] 深入理解計算機系統(第三版) Randal E.Bryant David R.O’Hallaron!
(參考文獻0分,缺失 -1分)
- 16 -
總結
- 上一篇: Java学习笔记11-2——Spring
- 下一篇: 青岛智能院助力智慧城市 打造智能产业“黄