计算机系统大作业-程序人生
?
計算機(jī)科學(xué)與技術(shù)學(xué)院
2021年5月
摘 ?要
本文介紹并詳細(xì)分析了hello程序的完整的一生:預(yù)處理,編譯,匯編,鏈接,在shell中運(yùn)行,在進(jìn)程中管理,接受I/O管理,終止回收。通過hello的一生,很好地對計算機(jī)系統(tǒng)的各部分知識進(jìn)行了一個較為完整的回顧和梳理。
關(guān)鍵詞:hello;計算機(jī)系統(tǒng);完整的一生;????????????????????????????
(摘要0分,缺失-1分,根據(jù)內(nèi)容精彩稱都酌情加分0-1分)
目 ?錄
第1章 概述
1.1 Hello簡介
1.2 環(huán)境與工具
1.3 中間結(jié)果
1.4 本章小結(jié)
第2章 預(yù)處理
2.1 預(yù)處理的概念與作用
2.2在Ubuntu下預(yù)處理的命令
2.3 Hello的預(yù)處理結(jié)果解析
2.4 本章小結(jié)
第3章 編譯
3.1 編譯的概念與作用
3.2 在Ubuntu下編譯的命令
3.3 Hello的編譯結(jié)果解析
3.4 本章小結(jié)
第4章 匯編
4.1 匯編的概念與作用
4.2 在Ubuntu下匯編的命令
4.3 可重定位目標(biāo)elf格式
4.4 Hello.o的結(jié)果解析
4.5 本章小結(jié)
第5章 鏈接
5.1 鏈接的概念與作用
5.2 在Ubuntu下鏈接的命令
5.3 可執(zhí)行目標(biāo)文件hello的格式
5.4 hello的虛擬地址空間
5.5 鏈接的重定位過程分析
5.6 hello的執(zhí)行流程
5.7 Hello的動態(tài)鏈接分析
5.8 本章小結(jié)
第6章 hello進(jìn)程管理
6.1 進(jìn)程的概念與作用
6.2 簡述殼Shell-bash的作用與處理流程
6.3 Hello的fork進(jìn)程創(chuàng)建過程
6.4 Hello的execve過程
6.5 Hello的進(jìn)程執(zhí)行
6.6 hello的異常與信號處理
6.7本章小結(jié)
第7章 hello的存儲管理
7.1 hello的存儲器地址空間
7.2 Intel邏輯地址到線性地址的變換-段式管理
7.3 Hello的線性地址到物理地址的變換-頁式管理
7.4 TLB與四級頁表支持下的VA到PA的變換
7.5 三級Cache支持下的物理內(nèi)存訪問
7.6 hello進(jìn)程fork時的內(nèi)存映射
7.7 hello進(jìn)程execve時的內(nèi)存映射
7.8 缺頁故障與缺頁中斷處理
7.9動態(tài)存儲分配管理
7.10本章小結(jié)
第8章 hello的IO管理
8.1 Linux的IO設(shè)備管理方法
8.2 簡述Unix IO接口及其函數(shù)
8.3 printf的實現(xiàn)分析
8.4 getchar的實現(xiàn)分析
8.5本章小結(jié)
結(jié)論
附件
參考文獻(xiàn)
第1章 概述
1.1 Hello簡介
P2P是指from program to process。在linux系統(tǒng)中,源文件hello.c記過預(yù)處理、編譯、匯編、鏈接生成可執(zhí)行文件hello。在輸入命令(./hello)啟動該程序后,shell為其fork,創(chuàng)建子進(jìn)程,然后hello就從程序變?yōu)榱诉M(jìn)程。
020是指from zero to zero。hello程序開始運(yùn)行成為進(jìn)程后,shell為其execve,映射虛擬內(nèi)存,調(diào)用程序入口時開始載入物理內(nèi)存,進(jìn)入main函數(shù)執(zhí)行目標(biāo)代碼,然后分配時間片,執(zhí)行邏輯控制流。hello程序運(yùn)行結(jié)束后,父進(jìn)程回收該子進(jìn)程,內(nèi)核刪除進(jìn)程產(chǎn)生的相關(guān)數(shù)據(jù)和分配的數(shù)據(jù)結(jié)構(gòu),恢復(fù)程序執(zhí)行前的狀態(tài),實現(xiàn)020。
1.2 環(huán)境與工具
硬件環(huán)境:X64 CPU;2GHz;2G RAM;256GHD Disk 以上
軟件環(huán)境:Windows7/10 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/優(yōu)麒麟 64位 以上
開發(fā)與調(diào)試工具:gcc、edb、readelf、Visual Studio等
1.3 中間結(jié)果
hello.i:預(yù)處理后的文件,加載了頭文件,進(jìn)行了宏替換,完成條件編譯。
hello.s:編譯后的匯編文件,已經(jīng)變?yōu)榱藚R編代碼
hello.o:匯編后的可重定位目標(biāo)文件,將匯編語言翻譯成機(jī)器語言指令,并將指令打包成可重定位目標(biāo)文件。
hello:?鏈接產(chǎn)生的可執(zhí)行目標(biāo)文件。
hello-oobj.txt:存儲了hello.0的反匯編文件。
hello-obj.txt:存儲了hello的反匯編文件。
1.4 本章小結(jié)
????本章對實驗內(nèi)容進(jìn)行了一個總體的概括,介紹了hello從產(chǎn)生到執(zhí)行的大致經(jīng)過,介紹了開發(fā)環(huán)境以及工具,簡述了寫論文過程中生成的中間文件。
(第1章0.5分)
第2章 預(yù)處理
2.1?預(yù)處理的概念與作用
(以下格式自行編排,編輯時刪除)
預(yù)處理的概念:預(yù)處理是在程序源代碼被編譯之前,由預(yù)處理器(cpp)根據(jù)以字符#開頭的命令,修改原始的C程序。這個過程并不對程序的源代碼語法進(jìn)行解析,但它會把源代碼分割或處理成為特定的符號為下一步的編譯做準(zhǔn)備工作。
預(yù)處理的作用:
展開所有宏定義,處理#define x y格式的語句,用y替代x;
加載頭文件,將#include格式的頭文件插入到預(yù)編譯指令的位置;
完成條件編譯,處理#if,#ifdef格式的語句;
刪除注釋。
2.2在Ubuntu下預(yù)處理的命令
應(yīng)截圖,展示預(yù)處理過程!
gcc -E hello.c -o hello.i
?? 圖2.2.1預(yù)處理過程
2.3 Hello的預(yù)處理結(jié)果解析
?
?
圖2.3.1預(yù)處理結(jié)果
打開hello.i文件后發(fā)現(xiàn),文件的內(nèi)容明顯增加,有3000多行,但是仍為可以閱讀的C語言文本文件。預(yù)處理器對源文件中的宏進(jìn)行了宏展開,將系統(tǒng)頭文件中的內(nèi)容直接插入到了程序文本中,同時也對#define相應(yīng)的符號進(jìn)行了替換。
2.4 本章小結(jié)
簡單介紹了文件在編譯之前的預(yù)處理過程,即.c文件生成.i文本文件的過程,對預(yù)處理的含義、具體執(zhí)行過程和預(yù)處理結(jié)果進(jìn)行了解析。
(第2章0.5分)
第3章 編譯
3.1 編譯的概念與作用
編譯的概念:編譯器將文本文件hello.i翻譯成文本文件hello.s,它包含一個匯編語言程序。
編譯的作用:編譯過程是指對預(yù)處理生存的.i文件進(jìn)行一系列詞法分析、語法分析、語義分析,最后優(yōu)化后生成相應(yīng)的匯編代碼文件。
3.2 在Ubuntu下編譯的命令
??gcc -S hello.c -o hello.s
?
?????????????????????圖3.2.1編譯過程
3.3 Hello的編譯結(jié)果解析
(以下格式自行編排,編輯時刪除)
此部分是重點,說明編譯器是怎么處理C語言的各個數(shù)據(jù)類型以及各類操作的。應(yīng)分3.3.1~ 3.3.x等按照類型和操作進(jìn)行分析,只要hello.s中出現(xiàn)的屬于大作業(yè)PPT中P4給出的參考C數(shù)據(jù)與操作,都應(yīng)解析。
3.3.1數(shù)據(jù)
????
?
?
?
???????????????圖3.3.1.1printf中的字符串
???i被存儲在棧中,地址是%rbp-4.
???
?
圖3.3.1.2局部變量i
???
?
圖3.3.1.3參數(shù)argc
4).main函數(shù)的參數(shù)argv數(shù)組:數(shù)組中的每一個元素都是一個指向字符類型的指針,數(shù)組的起始地址存放于棧中-32(%rbp)的位置。分別獲取了argv[2],argv[1],argv[3]的 地址,并將其地址處的內(nèi)容存儲到相應(yīng)的寄存器中,用于printf函數(shù)和atoi函數(shù)的參數(shù)傳遞。
?
圖3.3.1.4參數(shù)argv
3.3.2操作
????????1).算術(shù)操作:每次循環(huán)結(jié)束后執(zhí)行i++的操作
????????
?
圖3.3.2.1循環(huán)加一操作
????????2).關(guān)系操作:
???????????[1].判斷argc是否等于4:
??????????????
?
圖3.3.2.2判斷argc
???
?
圖3.3.2.3判斷for條件
3).控制轉(zhuǎn)移操作:本程序主要是指if條件分支引起的跳轉(zhuǎn)以及for循環(huán)分支引起的跳轉(zhuǎn)。它們主要通過關(guān)系操作cmpl進(jìn)行比較設(shè)置條件碼,之后根據(jù)條件碼進(jìn)行對應(yīng)的跳轉(zhuǎn)。
?
?
圖3.3.2.4跳轉(zhuǎn)
4).函數(shù)調(diào)用操作:在函數(shù)調(diào)用前,設(shè)置用于參數(shù)傳遞的寄存器的值,之后通過call指令進(jìn)行函數(shù)的調(diào)用,本程序主要有printf函數(shù)的調(diào)用,sleep函數(shù)的調(diào)用,atoi函數(shù)的調(diào)用,exit函數(shù)的調(diào)用,以及getchar函數(shù)的調(diào)用。
??????????
?
????????????
?
??????????????
????????????
?
?
?????????????????????????圖3.3.2.5函數(shù)調(diào)用
3.4 本章小結(jié)
介紹了編譯的概念和作用。通過hello程序展示了c語言轉(zhuǎn)換成匯編代碼的過程。介紹了匯編代碼如何實現(xiàn)變量、常量、傳遞參數(shù)以及分支和循環(huán)。編譯程序所做的工作。并對編譯的過程進(jìn)行進(jìn)一步的分析,加深了對c語言的數(shù)據(jù)與操作,對c語言翻譯成匯編語言的邏輯有進(jìn)一步的掌握。
(第3章2分)
第4章 匯編
4.1 匯編的概念與作用
匯編的概念:?匯編是通過匯編器,把匯編語言翻譯成機(jī)器語言的過程。
匯編的作用:將匯編語言程序翻譯成機(jī)器指令,并將這些指令打包成一種叫做可重定位目標(biāo)程序的格式,并將這個結(jié)果保留.o目標(biāo)文件中。
4.2 在Ubuntu下匯編的命令
gcc -c hello.s -o hello.o
?
圖4.2.1匯編過程
4.3 可重定位目標(biāo)elf格式
分析hello.o的ELF格式,用readelf等列出其各節(jié)的基本信息,特別是重定位項目分析。
ELF Headers:以 16B 的序列 Magic 開始,Magic 描述了生成該文件的系統(tǒng)的字的大小和字節(jié)順序,ELF 頭剩下的部分包含幫助鏈接器語法分析和解釋目標(biāo)文件的信息,其中包括 ELF 頭的大小、目標(biāo)文件的類型、機(jī)器類型、字節(jié)頭部表(section header table)的文件偏移,以及節(jié)頭部表中條目的大小和數(shù)量等信息。
?
圖4.3.1ELF頭信息
?
?
圖4.3.2節(jié)頭部表信息
3.查看符號表:symtab:存放程序中定義和引用的函數(shù)和全局變量的信息。
Ndx:ABS表示不該被重定位、UND表示未定義(在這個地方被引用,但是在其他地方進(jìn)行定義)、COM表示未初始化數(shù)據(jù)(未初始化的全局變量)
Bind:綁定屬性:全局符號、局部符號
Type:符號類型:函數(shù)、數(shù)據(jù)、源文件、節(jié)、未知
Value:.o.文件中是偏移量
?
圖4.3.3符號表信息
4.查看重定位條目:描述了需要進(jìn)行重定位的各種信息,包括需要進(jìn)行重定位符號的位置、重定位的方式、名字。
?
圖4.3.4重定位條目
4.4 Hello.o的結(jié)果解析
將反匯編后的指令存儲在hello-oobj中。
?
?
圖4.4.1匯編指令
對比:
1.代碼左邊多了機(jī)器碼;
2.hello.s中的操作數(shù)為十進(jìn)制,hello.o反匯編代碼中的操作數(shù)為十六進(jìn)制;
3.call跳轉(zhuǎn)指令,在hello.s文件中,直接加上跳轉(zhuǎn)函數(shù)名,在反匯編文件中,加上了跳轉(zhuǎn)的相對偏移地址,函數(shù)在鏈接之后才能確定執(zhí)行的地址,因此在.rela.text節(jié)中為其添加了重定位條目。說明機(jī)器語言的構(gòu)成,與匯編語言的映射關(guān)系。特別是機(jī)器語言中的操作數(shù)與匯編語言不一致,特別是分支轉(zhuǎn)移函數(shù)調(diào)用等。
4.5 本章小結(jié)
?????通過將hello.s匯編指令轉(zhuǎn)換成hello.o機(jī)器指令,通過readelf查看hello.o的ELF、反匯編的方式查看hello.o反匯編的內(nèi)容,比較其與hello.s之間的差別,以及學(xué)習(xí)匯編指令和機(jī)器指令之間的映射關(guān)系,更深刻地理解了匯編語言到機(jī)器語言實現(xiàn)地轉(zhuǎn)變,和這過程中為鏈接做出的準(zhǔn)備。
(第4章1分)
第5章 鏈接
5.1 鏈接的概念與作用
?????鏈接的概念:鏈接是將各種不同文件的代碼和數(shù)據(jù)部分收集(符號解析和重定位)起來并組合成一個單一文件的過程。
?????鏈接的作用:令源程序節(jié)省空間而未編入的常用函數(shù)文件進(jìn)行合并,生成可以正常工作的可執(zhí)行文件。這令分離編譯成為可能,節(jié)省了大量的工作空間。
5.2 在Ubuntu下鏈接的命令
命令:
ld-ohello-dynamic-linker/lib64/ld-linux-x86-64.so.2/usr/lib/x86_64-linux-gnu/crt1.o/usr/lib/x86_64-linux-gnu/crti.ohello.o/usr/lib/x86_64-linux-gnu/libc.so/usr/lib/x86_64-linux-gnu/crtn.o
?
圖5.2.1鏈接過程
5.3 可執(zhí)行目標(biāo)文件hello的格式
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
1.查看hello的ELF頭:
?
圖5.3.1ELF頭信息
由此可知hello文件類型為EXEC,即是一個可執(zhí)行目標(biāo)文件,文件中共有27個節(jié)。
2.查看節(jié)頭部表:
?
?
圖5.3.2節(jié)頭部表信息
由此可知文件中各個段的基本信息,從Size獲取各個段的大小,從Address可以獲得各個段的起始地址即為程序被載入虛擬地址后各段的起始地址,從offset可以獲得各個段在程序中的偏移量。
3.查看符號表:
?
?
圖5.3.3符號表信息
5.4 hello的虛擬地址空間
使用edb加載hello,查看本進(jìn)程的虛擬地址空間各段信息,并與5.3對照分析說明。
根據(jù)程序頭表查看各個段的信息:??
?
?????????????????????????圖5.4.1起始信息
代碼段從init 401000開始:
?
圖5.4.2代碼段
數(shù)據(jù)段:
?
圖5.4.3數(shù)據(jù)段
stack:
?圖5.4.4stack部分信息
?
5.5 鏈接的重定位過程分析
將hello的反匯編文件存儲在hello-obj.txt中:
?
?
?
?
?
?
圖5.5.1反匯編信息(以上這幾張圖是一起的)
對比hello.o:
?1.hello.o中的相對偏移地址到了hello中變成了虛擬內(nèi)存地址
2. hello中相對hello.o增加了許多的外部鏈接來的函數(shù),比如exit、printf等。
3. hello相對hello.o多了很多的節(jié)類似于.init,.plt等
4. hello.o中跳轉(zhuǎn)以及函數(shù)調(diào)用的地址在hello中都被更換成了虛擬內(nèi)存地址
查看hello.o的重定位條目并據(jù)此分析hello的重定位過程:
?
圖5.5.2重定位條目
1.重定位節(jié)和符號定義鏈接器將所有類型相同的節(jié)合并在一起后,這個節(jié)就作為可執(zhí)行目標(biāo)文件的節(jié)。然后鏈接器把運(yùn)行時的內(nèi)存地址賦給新的聚合節(jié),賦給輸入模塊定義的每個節(jié),以及賦給輸入模塊定義的每個符號,當(dāng)這一步完成時,程序中每條指令和全局變量都有唯一運(yùn)行時的地址。
2,重定位節(jié)中的符號引用這一步中,連接器修改代碼節(jié)和數(shù)據(jù)節(jié)中對每個符號的引用,使他們指向正確的運(yùn)行時地址。執(zhí)行這一步,鏈接器依賴于可重定位目標(biāo)模塊中稱為的重定位條目的數(shù)據(jù)結(jié)構(gòu)。
3.重定位條目當(dāng)編譯器遇到對最終位置未知的目標(biāo)引用時,它就會生成一個重定位條目。
5.6 hello的執(zhí)行流程
?
圖5.6.1edb中信息展示
0x401000 <_init>
0x401090 <puts@plt>
0x4010a0 <printf@plt>
0x4010b0 <getchar@plt>
0x4010c0 <atoi@plt>
0x4010d0 <exit@plt>
0x4010e0 <sleep@plt>
0x4010f0 <_start>
0x401120 <_dl_relocate_static_pie>
0x401125 <main>
0x4011c0 <__libc_csu_init>
0x401230 <__libc_csu_fini>
0x401238 <_fini>
5.7 Hello的動態(tài)鏈接分析
?
圖5.7.1got和plt的信息
在edb中找到0x403ff0和0x404000的位置
?
圖5.7.2調(diào)用init函數(shù)前的內(nèi)容
????一開始地址的字節(jié)都為0,調(diào)用_init函數(shù)之后GOT內(nèi)容產(chǎn)生變化,指向正確的內(nèi)存地址,下一次調(diào)用跳轉(zhuǎn)時可以跳轉(zhuǎn)到正確位置。
?
圖5.7.3調(diào)用init函數(shù)后內(nèi)容的變化
5.8 本章小結(jié)
本章介紹了鏈接的概念及作用,在Ubuntu下鏈接的命令行,并對hello的elf格式進(jìn)行了詳細(xì)的分析對比,并通過反匯編hello文件,將其與hello.o反匯編文件對比,詳細(xì)了解了重定位過程,遍歷了整個hello的執(zhí)行過程,在最后對hello進(jìn)行了動態(tài)鏈接分析,使得對hello的鏈接過程有了一個深刻的理解和體會。
(第5章1分)
第6章 hello進(jìn)程管理
6.1 進(jìn)程的概念與作用
?????進(jìn)程的概念:一個執(zhí)行中程序的實例。
?????進(jìn)程的作用:進(jìn)程主要為用戶提供了下列兩個假象
(1)一個獨立的邏輯流,提供程序獨占使用處理器的假象。
(2)一個私有的虛擬地址空間,提供程序獨占使用整個系統(tǒng)內(nèi)存的假象。
每次用戶通過向shell 輸入一個可執(zhí)行目標(biāo)文件的名字,運(yùn)行程序時, shell 就會創(chuàng)建一個新的進(jìn)程,然后在這個新進(jìn)程的上下文中運(yùn)行這個可執(zhí)行目標(biāo)文件。應(yīng)用程序也能夠創(chuàng)建新進(jìn)程,并且在這個新進(jìn)程的上下文中運(yùn)行它們自己的代碼或其他應(yīng)用程序。
6.2 簡述殼Shell-bash的作用與處理流程
(以下格式自行編排,編輯時刪除)
Shell-bash的作用:shell是一個命令解釋器,它解釋用戶輸入的命令并把它們送到內(nèi)核,用于用戶和系統(tǒng)的交互。
處理流程:
1.Shell首先從命令行中找出特殊字符(元字符),在將元字符翻譯成間隔符號。元字符將命令行劃分成小塊tokens。Shell中的元字符如下:SPACE , TAB , NEWLINE , & , ; , ( , ) ,< , > , |
2.程序塊tokens被處理,檢查看他們是否是shell中所引用到的關(guān)鍵字。
3.當(dāng)程序塊tokens被確定以后,shell根據(jù)aliases文件中的列表來檢查命令的第一個單詞。如果這個單詞出現(xiàn)在aliases表中,執(zhí)行替換操作并且處理過程回到第一步重新分割程序塊tokens。
4.Shell對~符號進(jìn)行替換。
5.Shell對所有前面帶有$符號的變量進(jìn)行替換。
6.Shell將命令行中的內(nèi)嵌命令表達(dá)式替換成命令;他們一般都采用$(command)標(biāo)記法。
7.Shell計算采用$(expression)標(biāo)記的算術(shù)表達(dá)式。
8.Shell將命令字符串重新劃分為新的塊tokens。這次劃分的依據(jù)是欄位分割符號,稱為IFS。缺省的IFS變量包含有:SPACE , TAB 和換行符號。
9.Shell執(zhí)行通配符* ? [ ]的替換。
10.shell把所有從處理的結(jié)果中用到的注釋刪除,並且按照下面的順序?qū)嵭忻畹臋z查:A. 內(nèi)建的命令B. shell函數(shù)(由用戶自己定義的)C. 可執(zhí)行的腳本文件(需要尋找文件和PATH路徑)
11.在執(zhí)行前的最后一步是初始化所有的輸入輸出重定向。
12.最后,執(zhí)行命令。
6.3 Hello的fork進(jìn)程創(chuàng)建過程
當(dāng)在終端中輸入./hello 學(xué)號 姓名?時間(比如120L0221 yqb 5)時。shell會通過上述流程處理,首先判斷出它不是內(nèi)置命令,所以會認(rèn)為它是一個當(dāng)前目錄下的可執(zhí)行文件hello。在加載此進(jìn)程時shell通過fork創(chuàng)建一個新的子進(jìn)程。新創(chuàng)建的子進(jìn)程幾乎但不完全與父進(jìn)程相同。子進(jìn)程得到與父進(jìn)程用戶級虛擬地址空間相同的(但是獨立的)一份副本,包括代碼和數(shù)據(jù)段、堆、共享庫和用戶棧。子進(jìn)程還獲得與父進(jìn)程任何打開文件描述符相同的副本,這就意味著當(dāng)父進(jìn)程調(diào)用fork時,子進(jìn)程可以讀寫父進(jìn)程中打開的任何文件。fork調(diào)用一次,返回兩次,子進(jìn)程與父進(jìn)程有不同的pid。父進(jìn)程和子進(jìn)程是并發(fā)運(yùn)行的獨立進(jìn)程,內(nèi)核可以任意方式交替執(zhí)行他們的邏輯控制流中的指令,所以這會導(dǎo)致我們不能簡單的憑直覺判斷指令執(zhí)行的順序,應(yīng)按照拓?fù)渑判蛐蛄袌?zhí)行。
6.4 Hello的execve過程
子進(jìn)程調(diào)用execve函數(shù)(傳入命令行參數(shù))在當(dāng)前進(jìn)程的上下文中加載并運(yùn)行一個新程序即hello程序。hello子進(jìn)程通過execve系統(tǒng)調(diào)用啟動加載器,加載器刪除子進(jìn)程所有的虛擬地址段,并創(chuàng)建一組新的代碼、數(shù)據(jù)、堆段。新的棧和堆段被初始化為0。通過將虛擬地址空間中的頁映射到可執(zhí)行文件的頁大小的片(chunk),新的代碼和數(shù)據(jù)段被初始化為可執(zhí)行文件中的內(nèi)容。最后加載器跳到_start地址,它最終調(diào)用hello的main 函數(shù)。除了一些頭部信息,在加載過程中沒有任何從磁盤到內(nèi)存的數(shù)據(jù)復(fù)制。直到CPU引用一個被映射的虛擬頁時才會進(jìn)行復(fù)制,此時,操作系統(tǒng)利用它的頁面調(diào)度機(jī)制自動將頁面從磁盤傳送到內(nèi)存。
6.5 Hello的進(jìn)程執(zhí)行
上下文信息:上下文就是內(nèi)核重新啟動一個被搶占的進(jìn)程所需要的狀態(tài),它由 通用寄存器、浮點寄存器、程序計數(shù)器、用戶棧、狀態(tài)寄存器、內(nèi)核棧和各種內(nèi) 核數(shù)據(jù)結(jié)構(gòu)等對象的值構(gòu)成。
進(jìn)程時間片:一個進(jìn)程執(zhí)行它的控制流的一部分的每一時間段叫做時間片。
調(diào)度:在進(jìn)程執(zhí)行的某些時刻,內(nèi)核可以決定搶占當(dāng)前進(jìn)程,并重新開始一個先前被強(qiáng)占的進(jìn)程。這種決策就叫調(diào)度(是由內(nèi)核中的調(diào)度器的代碼處理的)。當(dāng)內(nèi)核調(diào)度一個新的進(jìn)程的運(yùn)行的時,內(nèi)核就會搶占當(dāng)前進(jìn)程,通過使用一種上下文切換的較為高層的形式異常控制流將控制轉(zhuǎn)移到新的進(jìn)程。具體如下:內(nèi)核首先保存當(dāng)前進(jìn)程的上下文,之后恢復(fù)之前被搶占的進(jìn)程保存的上下文,將控制傳遞給這個恢復(fù)的進(jìn)程。
用戶模式和內(nèi)核模式:處理器通常使用一個寄存器提供兩種模式的區(qū)分,該寄存器描述了進(jìn)程當(dāng)前享有的特權(quán),當(dāng)沒有設(shè)置模式位時,進(jìn)程就處于用戶模式中,用戶模式的進(jìn)程不允許執(zhí)行特權(quán)指令,也不允許直接引用地址空間中內(nèi)核區(qū)內(nèi)的代碼和數(shù)據(jù);設(shè)置模式位時,進(jìn)程處于內(nèi)核模式,該進(jìn)程可以執(zhí)行指令集中的任何命令,并且可以訪問系統(tǒng)中的任何內(nèi)存位置。
具體分析hello的進(jìn)程執(zhí)行:初始時,運(yùn)行hello進(jìn)程,處于用戶模式。調(diào)用系統(tǒng)函數(shù)sleep后,進(jìn)入內(nèi)核模式,執(zhí)行另一個進(jìn)程,此時間片停止。倒計時結(jié)束后,發(fā)送中斷信號,轉(zhuǎn)回用戶模式,繼續(xù)執(zhí)行hello進(jìn)程,重復(fù)此過程直到結(jié)束。
6.6 hello的異常與信號處理
(以下格式自行編排,編輯時刪除)
?hello執(zhí)行過程中會出現(xiàn)哪幾類異常,會產(chǎn)生哪些信號,又怎么處理的。
?程序運(yùn)行過程中可以按鍵盤,如不停亂按,包括回車,Ctrl-Z,Ctrl-C等,Ctrl-z后可以運(yùn)行ps ?jobs ?pstree ?fg ?kill 等命令,請分別給出各命令及運(yùn)行結(jié)截屏,說明異常與信號的處理。
異常種類:中斷、陷阱、故障、終止。
????
可能會產(chǎn)生很多信號,根據(jù)信號種類執(zhí)行此信號的默認(rèn)行為,如果使用了signal函數(shù)則另行討論。
回車:不會產(chǎn)生什么變化,只是會空行而已。
?
圖6.6.1程序執(zhí)行時按下回車
Ctrl-z:會停止。
?
圖6.6.2程序執(zhí)行時按下ctrl-z
Ctrl-c:終止進(jìn)程。
?
圖6.6.3程序執(zhí)行時按下ctrl-c
Ctrl-z后運(yùn)行ps:?輸入ctrl-z,內(nèi)核會發(fā)送SIGSTP。SIGSTP默認(rèn)掛起前臺hello作業(yè),但?hello進(jìn)程并沒有回收,而是運(yùn)行在后臺下,通過ps指令可以對其進(jìn)行查看。
?
圖6.6.4ctrl-z后運(yùn)行ps
Ctrl-z后運(yùn)行jobs:
?
圖6.6.5ctrl-z后運(yùn)行jobs
Ctrl-z后運(yùn)行pstree:
?
圖6.6.5ctrl-z后運(yùn)行pstree
Ctrl-z后運(yùn)行fg:繼續(xù)剛才停止的進(jìn)程。
?
圖6.6.5ctrl-z后運(yùn)行fg
Ctrl-z后運(yùn)行kill:
?
圖6.6.5ctrl-z后運(yùn)行kill
6.7本章小結(jié)
本章了解了進(jìn)程的概念及作用和shell的作用和處理流程,分析了hello進(jìn)程的執(zhí)行過程以及fork和execve的作用,了解信號處理和hello進(jìn)程如何在內(nèi)核模式和用戶模式中反復(fù)跳躍運(yùn)行的。
????(第6章1分)
第7章 hello的存儲管理
7.1 hello的存儲器地址空間
邏輯地址:是指由程序hello產(chǎn)生的與段相關(guān)的偏移地址部分(hello.o)。
線性地址:是邏輯地址到物理地址變換之間的中間層。程序hello的代碼會產(chǎn)生邏輯地址,或者說是(即hello程序)段中的偏移地址,它加上相應(yīng)段的基地址就生成了一個線性地址。
虛擬地址:也就是線性地址。因為與虛擬內(nèi)存空間的概念類似,邏輯地址也是與實際物理內(nèi)存容量無關(guān)的,是hello中的虛擬地址。
物理地址:是指出現(xiàn)在CPU外部地址總線上的尋址物理內(nèi)存的地址信號,是地址變換的最終結(jié)果地址。如果啟用了分頁機(jī)制,那么hello的線性地址會使用頁目錄和頁表中的項變換成hello的物理地址;如果沒有啟用分頁機(jī)制,那么hello的線性地址就直接成為物理地址了。
7.2 Intel邏輯地址到線性地址的變換-段式管理
?一個邏輯地址由兩部份組成,段標(biāo)識符: 段內(nèi)偏移量。可以通過段標(biāo)識符的前13位,直接在段描述符表中找到一個具體的段描述符,Base字段表示包含段的首字節(jié)的線性地址,也就是一個段的開始位置的線性地址。
先檢查段選擇符中的TI字段,以決定段描述符保存在哪一個描述符表中;
由于一個段描述符是8字節(jié)長,因此她在GDT或LDT內(nèi)的相對地址是由段選擇符的最高13位的值乘以8得到;
Base + offset,得到要轉(zhuǎn)換的線性地址。
7.3 Hello的線性地址到物理地址的變換-頁式管理
頁式管理是一種內(nèi)存空間存儲管理的技術(shù),頁式管理分為靜態(tài)頁式管理和動態(tài)頁式管理。將各進(jìn)程的虛擬空間劃分成若干個長度相等的頁(page),頁式管理把內(nèi)存空間按頁的大小劃分成片或者頁面(page frame),然后把頁式虛擬地址與內(nèi)存地址建立一一對應(yīng)頁表,并用相應(yīng)的硬件地址變換機(jī)構(gòu),來解決離散地址變換問題。頁式管理采用請求調(diào)頁或預(yù)調(diào)頁技術(shù)實現(xiàn)了內(nèi)外存存儲器的統(tǒng)一管理。
頁表就是一個頁表條目的數(shù)組。虛擬地址空間中的每個頁在頁表中一個固定的偏移量處都有一個PTE。PTE包含了一個有效位和一個n位字段,有效位表明了該虛擬頁當(dāng)前是否被緩存在DRAM中。因為DRAM是全相聯(lián)的,所以任意物理頁都可包含任意虛擬頁。
n位的虛擬地址包含兩個部分:一個p位的虛擬頁面偏移(VPO)和一個n-p位的虛擬頁號(VPN)。MMU利用VPN來選擇適當(dāng)?shù)腜TE.將頁表條目中的物理頁號和VPO串聯(lián)起來就是相應(yīng)的物理地址。因為物理和虛擬頁面都是P字節(jié)的,所以物理頁面偏移和虛擬頁面偏移是相同的。
7.4 TLB與四級頁表支持下的VA到PA的變換
TLB是MMU中的一個關(guān)于PTE的小的緩存,有了TLB后,VPN又分為了TLB標(biāo)記(TLBT)和TLB索引(TLBI),TLB的機(jī)制與全相聯(lián)的cache的機(jī)制相同,如果TLB有T = 2s個組,那么TLB索引(TLBI)是由VPN的s個最低位組成的,TLB標(biāo)記(TLBT)是由VPN中剩余的位組成。
引入多級頁表后,VPN被劃分成了多個區(qū)域,例如使用k級頁表,VPN被劃分成了k個VPN,每個VPNi都是一個到第i級頁表的索引,第k個VPN中存儲著VPN對應(yīng)的PPN。
CPU產(chǎn)生一個VA,MMU在根據(jù)VPN在TLB中搜索PTE,若命中,MMU取出相應(yīng)的PTE,根據(jù)PTE將VA翻譯成PA;若沒命中,則通過多級頁表查詢PTE是否在頁中,若在頁中,找到對應(yīng)的PIE,MMU將VA翻譯成PA,若沒有在頁中,則進(jìn)行缺頁處理
7.5 三級Cache支持下的物理內(nèi)存訪問
CPU發(fā)送一條虛擬地址,隨后MMU按照上述操作獲得了物理地址PA。根據(jù)cache大小組數(shù)的要求,將PA分為CT(標(biāo)記位)CS(組號),CO(偏移量)。根據(jù)CS尋找到正確的組,比較每一個cacheline是否標(biāo)記位有效以及CT是否相等。如果命中就直接返回想要的數(shù)據(jù),如果不命中,就依次去L2,L3,主存判斷是否命中,當(dāng)命中時,將數(shù)據(jù)傳給CPU同時更新各級cache的cacheline(如果cache已滿則要采用換入換出策略)。
7.6 hello進(jìn)程fork時的內(nèi)存映射
當(dāng)fork 函數(shù)被shell調(diào)用時,內(nèi)核為hello進(jìn)程創(chuàng)建各種數(shù)據(jù)結(jié)構(gòu),并分配給它一個唯一的PID 。為了給hello進(jìn)程創(chuàng)建虛擬內(nèi)存,它創(chuàng)建了hello進(jìn)程的mm_struct 、區(qū)域結(jié)構(gòu)和頁表的原樣副本。它將兩個進(jìn)程中的每個頁面都標(biāo)記為只讀,并將兩個進(jìn)程中的每個區(qū)域結(jié)構(gòu)都標(biāo)記為私有的寫時復(fù)制。
當(dāng)fork 在hello進(jìn)程中返回時,hello進(jìn)程現(xiàn)在的虛擬內(nèi)存剛好和調(diào)用fork 時存在的虛擬內(nèi)存相同。當(dāng)這兩個進(jìn)程中的任一個后來進(jìn)行寫操作時,寫時復(fù)制機(jī)制就會創(chuàng)建新頁面,因此,也就為每個進(jìn)程保持了私有地址空間的抽象概念。
7.7 hello進(jìn)程execve時的內(nèi)存映射
(以下格式自行編排,編輯時刪除)
1.刪除已存在的用戶區(qū)域:刪除當(dāng)前進(jìn)程虛擬地址的用戶部分中已存在的區(qū)域結(jié)構(gòu)。
2.映射私有區(qū)域:為新程序的代碼、數(shù)據(jù)、bss和棧區(qū)域創(chuàng)建新的區(qū)域結(jié)構(gòu)。所有這些新的區(qū)域都是私有的,寫時復(fù)制的。代碼和數(shù)據(jù)區(qū)域被映射為hello文件中的.test和.data區(qū)。bss區(qū)域是請求二進(jìn)制0的,映射到匿名文件,其大小包含在a.out當(dāng)中。棧和堆區(qū)域也是請求二進(jìn)制零的,初始長度為零。
3.映射共享區(qū)域hello 程序與共享對象 libc.so 鏈接,libc.s是動態(tài)鏈 接到這個程序中的,然后再映射到用戶虛擬地址空間中的共享區(qū)域內(nèi)。
4.設(shè)置程序計數(shù)器PC:execve做的最后一件事情就是設(shè)置當(dāng)前進(jìn)程上下文中的程序計數(shù)器,指向代碼區(qū)域的入口點。
7.8 缺頁故障與缺頁中斷處理
缺頁故障的概念:缺頁故障:當(dāng)CPU想要讀取虛擬內(nèi)存中的某個數(shù)據(jù),而這一片數(shù)據(jù)恰好存放在主存當(dāng)中時,就稱為頁命中。相對的,如果DRAM緩存不命中,則稱之為缺頁。如果CPU嘗試讀取一片內(nèi)存而這片內(nèi)存并沒有緩存在主存當(dāng)中時,就會觸發(fā)一個缺頁異常。
缺頁中斷處理:發(fā)生缺頁故障時,處出發(fā)缺頁異常處理程序,缺頁處理程序確認(rèn)出物理內(nèi)存中的犧牲頁,如果這個頁已經(jīng)被修改了,則把它換到磁盤。缺頁處理程序調(diào)入新的頁面,并更新內(nèi)存中的PTE,缺頁處理程序返回到原來的進(jìn)程,再次執(zhí)行導(dǎo)致缺頁的命令。CPU將引起缺頁的虛擬地址重新發(fā)送給MMU。因為虛擬頁面已經(jīng)緩存在物理內(nèi)存中,所以就會命中。
7.9動態(tài)存儲分配管理
動態(tài)儲存分配管理使用動態(tài)內(nèi)存分配器來進(jìn)行。動態(tài)內(nèi)存分配器維護(hù)著一個進(jìn)程的虛擬內(nèi)存區(qū)域,稱為堆。分配器將堆視為一組不同大小的塊的集合來維護(hù)。每個塊就是一個連續(xù)的虛擬內(nèi)存片,要么是已分配的,要么是空閑的。已分配的塊顯式地保留為供應(yīng)用程序使用。空閑塊可以用來分配。空閑塊保持空閑,直到它顯式地被應(yīng)用所分配。一個已分配的塊保持已分配的狀態(tài),直到它被釋放,這種釋放要么是應(yīng)用程序顯式執(zhí)行的,要么是內(nèi)存分配器自身隱式執(zhí)行的。動態(tài)內(nèi)存分配主要有兩種基本方法與策略:
帶邊界標(biāo)簽的隱式空閑鏈表分配器管理:
帶邊界標(biāo)記的隱式空閑鏈表的每個塊是由一個字的頭部、有效載荷、可能的???????
額外填充以及一個字的尾部組成的。
隱式空閑鏈表:在隱式空閑鏈表中,因為空閑塊是通過頭部中的大小字段隱含地連接著的。分配器可以通過遍歷堆中所有的塊,從而間接地遍歷整個空閑塊的集合。其中,一個設(shè)置了已分配的位而大小為零的終止頭部將作為特殊標(biāo)記的結(jié)束塊。
當(dāng)一個應(yīng)用請求一個k字節(jié)的塊時,分配器搜索空閑鏈表,查找一個足夠大的可以放置所請求塊的空閑塊。分配器有三種放置策略:首次適配、下一次適配合最佳適配。分配完后可以分割空閑塊減少內(nèi)部碎片。同時分配器在面對釋放一個已分配塊時,可以合并空閑塊,其中便利用隱式空閑鏈表的邊界標(biāo)記來進(jìn)行合并。
顯式空間鏈表管理:
顯式空閑鏈表是將空閑塊組織為某種形式的顯式數(shù)據(jù)結(jié)構(gòu)。因為根據(jù)定義,程序不需要一個空閑塊的主體,所以實現(xiàn)這個數(shù)據(jù)結(jié)構(gòu)的指針可以存放在這些空閑塊的主體里面。如,堆可以組織成一個雙向鏈表,在每個空閑塊中,都包含一個前驅(qū)與一個后繼指針。
顯式空閑鏈表:在顯式空閑鏈表中。可以采用后進(jìn)先出的順序維護(hù)鏈表,將最新釋放的塊放置在鏈表的開始處,也可以采用按照地址順序來維護(hù)鏈表,其中鏈表中每個塊的地址都小于它的后繼地址,在這種情況下,釋放一個塊需要線性時間的搜索來定位合適的前驅(qū)。
7.10本章小結(jié)
本章介紹了hello的存儲器地址空間、intel的段式管理、hello的頁式管理,在指定環(huán)境下介紹了 VA 到 PA 的變換、物理內(nèi)存訪問,還介紹 hello 進(jìn)程 fork 時的內(nèi)存映射、 execve 時的內(nèi)存映射、缺頁故障與缺頁中斷處理、動態(tài)存儲分配管理。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO設(shè)備管理方法
設(shè)備的模型化:文件
設(shè)備管理:unix io接口
一個Linux文件就是一個m個字節(jié)的序列:B0,B1,B2….Bk,….,Bm-1
所有的I/O設(shè)備都被模型化為文件而所有的輸入和輸出都被當(dāng)作對相應(yīng)文件的讀和寫來執(zhí)行。這種將設(shè)備優(yōu)雅地映射為文件的方式,允許Linux 內(nèi)核引出一個簡單、低級的應(yīng)用接口,稱為Unix I/O,這使得所有的輸入和輸出都能以一種統(tǒng)一且一致的方式來執(zhí)行。
8.2 簡述Unix IO接口及其函數(shù)
(以下格式自行編排,編輯時刪除)
Unix IO接口:
打開文件。一個應(yīng)用程序通過要求內(nèi)核打開相應(yīng)的文件,來宣告他想要訪問一個I/O設(shè)備。內(nèi)核返回一個小的非負(fù)整數(shù),叫做描述符,他在后續(xù)對此文件的所有操作中標(biāo)識這個文件。
Linux shell創(chuàng)建的每個進(jìn)程開始時都有三個打開的文件:標(biāo)準(zhǔn)輸入(文件描述符0)、標(biāo)準(zhǔn)輸出(描述符為1),標(biāo)準(zhǔn)出錯(描述符為2)。頭文件<unistd.h>定義了常量STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,他們可用來代替顯式的描述符值。
函數(shù):
1.open()函數(shù)
功能描述:用于打開或創(chuàng)建文件,在打開或創(chuàng)建文件時可以指定文件的屬性及用戶的權(quán)限等各種參數(shù)。
函數(shù)原型:int open(const char *pathname,int flags,int perms)
參數(shù):pathname:被打開的文件名(可包括路徑名如"dev/ttyS0")flags:文件打開方式,
返回值:成功:返回文件描述符;失敗:返回-1
2.close()函數(shù)
功能描述:用于關(guān)閉一個被打開的的文件
所需頭文件: #include <unistd.h>
函數(shù)原型:int close(int fd)
參數(shù):fd文件描述符
函數(shù)返回值:0成功,-1出錯
3.read()函數(shù)
功能描述: 從文件讀取數(shù)據(jù)。
所需頭文件: #include <unistd.h>
函數(shù)原型:ssize_t read(int fd, void *buf, size_t count);
參數(shù):fd:將要讀取數(shù)據(jù)的文件描述詞。buf:指緩沖區(qū),即讀取的數(shù)據(jù)會被放到這個緩沖區(qū)中去。count: 表示調(diào)用一次read操作,應(yīng)該讀多少數(shù)量的字符。
返回值:返回所讀取的字節(jié)數(shù);0(讀到EOF);-1(出錯)。
4.write()函數(shù)
功能描述: 向文件寫入數(shù)據(jù)。
所需頭文件: #include <unistd.h>
函數(shù)原型:ssize_t write(int fd, void *buf, size_t count);
返回值:寫入文件的字節(jié)數(shù)(成功);-1(出錯)
5.lseek()函數(shù)
功能描述: 用于在指定的文件描述符中將將文件指針定位到相應(yīng)位置。
所需頭文件:#include <unistd.h>,#include <sys/types.h>
函數(shù)原型:off_t lseek(int fd, off_t offset,int whence);
參數(shù):fd;文件描述符。offset:偏移量,每一個讀寫操作所需要移動的距離,單位是字節(jié),可正可負(fù)(向前移,向后移)
返回值:成功:返回當(dāng)前位移;失敗:返回-1
8.3 printf的實現(xiàn)分析
[轉(zhuǎn)]printf 函數(shù)實現(xiàn)的深入剖析 - Pianistx - 博客園
首先查看printf函數(shù):
?
圖8.3.1printf函數(shù)源碼
發(fā)現(xiàn)它調(diào)用了兩個函數(shù),分別是vsprintf和write。
再看vsprintf函數(shù):
?
圖8.3.2vsprintf函數(shù)源碼
vsprintf的作用就是格式化。它接受確定輸出格式的格式字符串fmt。用格式字符串對個數(shù)變化的參數(shù)進(jìn)行格式化,產(chǎn)生格式化輸出。
再看write函數(shù):
?????
?
圖8.3.3write函數(shù)
write,顧名思義:寫操作,把buf中的i個元素的值寫到終端。
從vsprintf生成顯示信息,到write系統(tǒng)函數(shù),到陷阱-系統(tǒng)調(diào)用 int 0x80或syscall等.
字符顯示驅(qū)動子程序:從ASCII到字模庫到顯示vram(存儲每一個點的RGB顏色信息)。
顯示芯片按照刷新頻率逐行讀取vram,并通過信號線向液晶顯示器傳輸每一個點(RGB分量)。
8.4 getchar的實現(xiàn)分析
首先查看getchar函數(shù):
?
圖8.4.1getchar函數(shù)源碼
通過分析可知,getchar調(diào)用了一個read函數(shù),將整個緩沖區(qū)都讀到了buf里面,然后返回緩沖區(qū)的長度。如果buf長度為0,getchar才會調(diào)用read函數(shù),否則是直接將保存的buf中的最前面的元素返回。
異步異常-鍵盤中斷的處理:鍵盤中斷處理子程序。接受按鍵掃描碼轉(zhuǎn)成ascii碼,保存到系統(tǒng)的鍵盤緩沖區(qū)。
getchar等調(diào)用read系統(tǒng)函數(shù),通過系統(tǒng)調(diào)用讀取按鍵ascii碼,直到接受到回車鍵才返回。
8.5本章小結(jié)
本章主要介紹了Linux的IO設(shè)備管理方法、Unix IO接口及其函數(shù),分析了printf函數(shù)和getchar函數(shù)。
(第8章1分)
結(jié)論
用計算機(jī)系統(tǒng)的語言,逐條總結(jié)hello所經(jīng)歷的過程。
你對計算機(jī)系統(tǒng)的設(shè)計與實現(xiàn)的深切感悟,你的創(chuàng)新理念,如新的設(shè)計與實現(xiàn)方法。
hello所經(jīng)歷的過程:
1.預(yù)處理:將hello.c調(diào)用的所有外部的庫拓展到hello.i文件中,宏命令被處理,但總體其實沒什么改變;
2.編譯:將hello.i編譯得到匯編代碼文件hello.s,被編譯為匯編代碼;
3.匯編:將hello.s匯編成為二進(jìn)制可重定位目標(biāo)文件hello.o,被編譯為機(jī)器代碼;
4.鏈接:將hello.o與可重定位目標(biāo)文件和動態(tài)鏈接庫鏈接成為可執(zhí)行目標(biāo)程序hello;
5.運(yùn)行:shell中運(yùn)行hello(我使用的是./hello 1111 yqb 1);
6.創(chuàng)建子進(jìn)程:shell進(jìn)程調(diào)用fork函數(shù)創(chuàng)建子進(jìn)程;
7.運(yùn)行程序:shell調(diào)用execve函數(shù),execve調(diào)用啟動加載器,映射虛擬內(nèi)存,進(jìn)入程序入口后程序開始載入物理內(nèi)存,然后進(jìn)入 main函數(shù);
8.執(zhí)行指令:CPU為其分配時間片,在一個時間片中,hello享有CPU資源,順序執(zhí)行自己的控制邏輯流;
9.訪問內(nèi)存:MMU將程序中使用的虛擬內(nèi)存地址通過頁表映射成物理地址;
10.動態(tài)申請內(nèi)存:printf會調(diào)用malloc向動態(tài)內(nèi)存分配器申請堆中的內(nèi)存;
11.信號:如果運(yùn)行途中鍵入Ctrl-C、Ctrl-Z則調(diào)用shell的信號處理函數(shù)分別停止、掛起;
12.結(jié)束:shell父進(jìn)程回收子進(jìn)程,內(nèi)核刪除為這個進(jìn)程創(chuàng)建的所有數(shù)據(jù)結(jié)構(gòu)。
我對計算機(jī)系統(tǒng)的感悟:
以前使用電腦時從來沒有深入探究過一個程序到底是怎么運(yùn)行的,只是動動鼠標(biāo)或者輸入一段命令就可以看到結(jié)果,但通過了本學(xué)期對計算機(jī)系統(tǒng)的學(xué)習(xí)后,我了解了每天都在使用的計算機(jī)卻有如此復(fù)雜的體系結(jié)構(gòu),從最底層的硬件設(shè)計,再到指令的運(yùn)作,再到進(jìn)程和存儲的邏輯,一個簡單的hello程序卻也需要如此復(fù)雜的一套運(yùn)作流程,著實令我感到驚嘆。
但同時,我認(rèn)為計算機(jī)系統(tǒng)確實有很多知識是晦澀難懂并且非常的抽象的,并不是看看書本就可以理解的,只能是通過查閱大量的資料和詢問老師才有可能弄懂,計算機(jī)系統(tǒng)的奧秘還是需要我們細(xì)細(xì)體會。
(結(jié)論0分,缺失 -1分,根據(jù)內(nèi)容酌情加分)
附件
列出所有的中間產(chǎn)物的文件名,并予以說明起作用。
hello.i:預(yù)處理后的文件,加載了頭文件,進(jìn)行了宏替換,完成條件編譯。
hello.s:編譯后的匯編文件,已經(jīng)變?yōu)榱藚R編代碼
hello.o:匯編后的可重定位目標(biāo)文件,將匯編語言翻譯成機(jī)器語言指令,并將指令打包成可重定位目標(biāo)文件。
hello:?鏈接產(chǎn)生的可執(zhí)行目標(biāo)文件。
hello-oobj.txt:存儲了hello.0的反匯編文件。
hello-obj.txt:存儲了hello的反匯編文件。
(附件0分,缺失 -1分)
參考文獻(xiàn)
? ? ? ? ?(往CSDN上傳圖片是真費勁!)
(參考文獻(xiàn)0分,缺失 -1分)
總結(jié)
以上是生活随笔為你收集整理的计算机系统大作业-程序人生的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何手动给Docker容器设置静态IP
- 下一篇: 基于ssm的航空订票系统