1. 程式人生 > >深入理解計算機系統大作業

深入理解計算機系統大作業

摘要

本論文從一個程式檔案hello.c出發,通過講述該檔案實現P2P,O2O的過程,簡單地展現了計算機系統的工作原理,並且回顧了許多實用的工具。
關鍵詞:P2P,O2O,計算機系統,程式;

第1章 概述

1.1 Hello簡介

P2P

1.編譯過程
圖1-1 編譯過程
2. 建立並執行程序 通過給予上下文形成程序,並放在系統中執行 。

O2O

shell執行hello程序,為其映射出虛擬記憶體,然後在開始執行程序的時候分配並載入實體記憶體,開始執行hello的程式,將其output的東西顯示到螢幕,然後hello程序結束,shell回收記憶體空間。

1.2 環境與工具

硬體環境: X64CPU; 8GHz; 8GRAM; 1TB HD;
軟體環境: Windows10 64位;VMware14.12; Ubuntu 16.04 LTS 64位;
工具:gcc,gdb,cpp,ccl,as,ld,readelf等。

1.3 中間結果

hello.i
hello.c檔案通過預處理後得到的新的程式文字檔案,對於包含檔案,巨集定義以及條件編譯進行了處理;
hello.s
hello.i檔案通過編譯後得到的由組合語言編寫的文字檔案,將高階語言轉換成了對應的組合語言;
hello.o
hello.s文佳彙編後得到的二進位制檔案,可用於與其他可重定位目標檔案連結形成可執行檔案;
hello


可執行目標檔案,在主機端輸入./hello後可執行程式,完成程式的預期任務。

1.4 本章小結

關於hello.c P2P,O2O的粗略介紹。

第2章 預處理

2.1 預處理的概念與作用

前處理器(cpp)根據義字元#開頭的命令,修改開始的c程式。比如hello.c中第一行的#include<stdio.h>命令告訴前處理器讀取系統標頭檔案stdio.h的內容,並插入到程式文字中;又比如,用define設定了一個巨集,前處理器會將程式中所有的該巨集替換掉(除此之外,當然還有條件編譯)。結果得到另一個程式,hello.i。

2.2在Ubuntu下預處理的命令

cpp hello.c > hello.i
圖2-1輸入命令前,一個.c檔案

圖2-2輸入命令
圖2-3輸入命令後,多了一個hello.i的程式檔案

2.3 Hello的預處理結果解析

hello.i可作為文字檔案開啟,該文字的最後末端的內容即是hello.c的主體內容,而hello.i前面還有大量的文字,包括各種各樣的定義,系統內的檔案引用,可見是將hello.c內預處理部分(主要是三個標頭檔案)經過了預處理,將內容插入到了程式中,成為了一個新的程式。

2.4 本章小結

預處理的主要三個功能就是處理巨集定義,插入包含檔案的內容,以及依據條件編譯。

第3章 編譯

3.1 編譯的概念與作用

編譯器(ccl)將文字檔案hello.i翻譯成文字檔案hello.s,包含一個組合語言程式。

3.2 在Ubuntu下編譯的命令

gcc -S hello.c -o hello.s

圖3-1輸入命令
圖3-2生成一個新的文字檔案hello.s

3.3 Hello的編譯結果解析

hello編譯結果
3.3.1資料傳送指令mov、movw,movsbw
一般用於賦初值,資料更換暫存器(具體目的包括輸入、輸出等)等
賦初值
賦初值,利用了棧空間,l(movl)表示按4位元組傳送

3.3.2壓入和彈出棧資料push、pop
壓入棧
利用棧空間 將暫存器%rbp中的資料壓入棧中(一般是(%rsp-8)所示記憶體地址)

3.3.3算數和邏輯運算leaq、add、not、and、sal、shr等
包括載入有效地址、加減乘除運算、邏輯運算、移位運算

leaq
leaq載入有效地址,類似於mov指令

減法
sub減法

加法
add加法

此外還有mul,imul乘法操作;div,idiv除法操作;and,or,xor,not邏輯運算;sal,shl,sar,shr移位運算 。

3.3.4控制操作cmp、test、set、jmp
比較(設定條件碼)、跳轉、由此可做到條件語句、迴圈語句
迴圈
判斷棧中資料與9的大小,決定是否跳轉其中.L3 .L4(按順序,L4在L3前)形成了迴圈語句,對應於hello.c中的for語句;
if
這是一個條件跳轉語句,對應於hello.c中的if語句

3.3.5函式呼叫call、ret
也可由此實現遞迴

call
呼叫函式,螢幕顯示

ret
ret函式返回,類似於return 0;

3.3.6全域性變數
常量
對應於hello.c中的int sleepsecs =2.5,由於int定義為整形數,所以此處給的空間為4個位元組

3.4 本章小結

組合語言相較於一般的高階語言,更加展現了機器實現操作的步驟和思路,也給出了許多高階語言無法給出的資訊(暫存器中的資料,棧的空間使用情況),而且可讀性很高。

第4章 彙編

4.1 彙編的概念與作用

彙編器(as)將hello.s翻譯成機器語言指令,把這些指令打包成一種叫做可重定位目標程式的格式,並將結果儲存在目標檔案hello.o中。hello.o是一個二進位制檔案(0/1)。

4.2 在Ubuntu下彙編的命令

as hello.s -o hello.o
圖4-1 輸入命令
圖4-2 出現了一個新的二進位制檔案hello.o

4.3 可重定位目標elf格式

4-2-1
4-2-2
可見其包含elf頭表,節頭表,重定位節和一個符號表重定位專案中給出了偏移量、資訊、型別、符號值、符號名稱等基本資訊,如.rela.text中:

  1. 偏移量表示他目前的相對地址(未連結前)
  2. 資訊表示他的值
  3. 型別比如R_X86_64_PC32表示重定位一個使用32位PC相對地址的引用
  4. 符號值和符號名稱表示引用的符號。 分析hello.o的ELF格式,用readelf等列出其各節的基本資訊,特別是重定位專案分析。

4.4 Hello.o的結果解析

4-4
機器語言的一條指令一般是由若干個位元組組成,包括指令、常數。
如b8 00 00 00 00前一個b8表示mov到%eax的指令,後面的八個零表示常數0x0(4位元組,小端表示)
b8 00 00 00 00 mov 0x0 , %eax

在跳轉時,反彙編檔案跳轉命令後直接接表示偏移量的數字
如:jmp 6fje 2bcallq 21<main+0x21>
而機器語句中則是依據當前語句與要跳轉到的語句偏移量的差,
如:26:e8 00 00 00 00 call 2b
由於0x26(當前PC相對偏移量)+0x5(5個位元組) = 0x2b,所以按順序結構中間相差0個位元組,即00 00 00 00

4.5 本章小結

彙編主要表現了機器語句的構造(章4 Y86-64),通過彙編,得到.o檔案(二進位制),機器才可以處理該檔案。通過反彙編與.s檔案的比較可以發現真正的機器指令思路上大體與彙編相同,但數的處理上會稍有不同。

第5章 連結

5.1 連結的概念與作用

hello程式呼叫了printf函式,printf函式存在於一個名為printf.o的單獨地預編譯好了的目標檔案中,連結器(ld)就負責處理這種合併,結果就得到hello檔案,一個可執行目標檔案。

5.2 在Ubuntu下連結的命令

ld hello.o -lc -o hello.out 或gcc hello.o -o hello.out
最簡單的生成可執行檔案的方法: gcc -o hello hello.c
圖-5-1
簡單執行hello
hello

5.3 可執行目標檔案hello的格式

1
23456可見包含一個elf頭表,29個節頭,1個程式頭,2個重定位節,2個符號表等,相比之前多了很多內容。圖中含有地址,大小等資訊

5.4 hello的虛擬地址空間

5-4
虛擬地址從0x00400000開始,到0x004001000
與5.3對照
程式頭
可見若干程式頭,包括:PHDR INTER PLOAD NOTEGNU_EH_FRAME GNU_STACK GNU_RELRO

5.5 連結的重定位過程分析

1.hello的內容較多,多出來很多函式puts,printf,sleep等,還有節.init .plt等
2.對函式引用的差別比較明顯

hello
hello

hello.o
hello.o
可見hello主要是跳轉向<mian+偏移量>,而hello則是直接跳向記憶體地址<函式名>,說明在連線的過程中,重定位已經完成,虛擬地址空間分配。
3. 從節頭數量看,hello也會比較多 hello.o的節頭有13個,和hello的節頭有29個
hello.o
hello.o

hello
hello

5.6 hello的執行流程

載入:_dl_start _dl_init
開始執行:_start _libc_start_main _init
執行main:_main _printf _exit _sleep _getchar _dl_runtime_resolve_xsave _dl_fixup _dl_lookup_symbol_x
退出:exit

5.7 Hello的動態連結分析

在edb除錯之後,原先0x00600a10開始的global_offset表全部成0,在執行_dl_init之後被賦上了相應的偏移量。說明_dl_init操作是給程式賦上當前執行的記憶體地址偏移量。

5.8 本章小結

通過與外部函式的連結,形成一個可以在機器上執行的檔案,在連結的過程中,主要處理了符號解析和重定位的問題,最終使得我們編寫成的簡單的程式檔案成為一個可以在機器環境中呼叫空間資源並處理問題的有效程式碼。

第6章 hello程序管理

6.1 程序的概念與作用

程序(Process)是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位,是作業系統結構的基礎。

6.2 簡述殼Shell-bash的作用與處理流程

shell是一個應用程式,作業系統中提供了一個使用者與系統核心進行互動的介面。
處理流程:1.讀取使用者的輸入 ;2.分析輸入內容,獲得輸入引數; 3.如果是核心命令則直接執行,否則呼叫相應的程式執行命令; 4.在程式執行期間,shell需要監視鍵盤的輸入內容,並且做出相應的反應.

6.3 Hello的fork程序建立過程

fork
fork

6.4 Hello的execve過程

execve執行時,先是從可執行檔案中載入的內容,然後是執行時的堆疊和共享庫的儲存器對映區域。
新的程式典型的棧幀:
execve

6.5 Hello的程序執行

上下文切換

6.6 hello的異常與訊號處理

C
輸入Ctrl+C,程序直接結束,該操作是向程序傳輸sigint訊號,終止前臺作業
Z
輸入Ctrl+Z, 程序停止 ,該操作是傳輸sigtstp訊號,停止前臺作業,不結束程序,輸入ps後可見hello仍在。
E
亂按回車,除了換行,不受影響

fg
Ctrl-z後可以執行fg命令,停止的程序繼續執行完成

jobs
Ctrl-z後可以執行jobs命令,可返回上一條指令結果的內容

pstree
Ctrl-z後可以執行pstree命令,可顯示程序樹
killkill命令可想制定程序傳送制定訊號,向PID為2789的程序hello傳送序號為2的訊號(sigint,等同於Ctrl+C),發現程序終止。

6.7本章小結

程序在shell的環境下用fork,wait建立並回收子程式,用execve載入新的程式,用鍵盤、函式反覆地傳送、捕獲、接收、處理/放棄訊號,一會執行程式一會處理訊號。

第7章 hello的儲存管理

7.1 hello的儲存器地址空間

邏輯地址:其實指的是偏移量,如21<main+0x21>
線性地址(虛擬地址):虛擬地址空間中的地址,可以保證每個程序擁有相同的地址空間,而且簡化了記憶體管理。0x00400000,幾乎所有的程序的使用者空間都由此開始。
實體地址:記憶體地址,是真實且與記憶體空間一一對應的地址

7.2 Intel邏輯地址到線性地址的變換-段式管理

先將邏輯地址分成段選擇符+段描述符的判別符(TI)+地址偏移量的形式,然後先判斷TI欄位,看看這個段描述符究竟是區域性段描述符(ldt)還是全域性段描述符(gdt),然後再將其組合成段描述符+地址偏移量的形式,這樣就轉換成線性地址了

7.3 Hello的線性地址到實體地址的變換-頁式管理

先將虛擬地址分為虛擬頁號(VPN),虛擬頁偏移量(VPO),依據VPN(TLBT+TLBI)先在TLB中尋找,若找不到,則在快取記憶體/記憶體中尋找,若找到對應的物理頁號(PPN),再將PPN與VPO組合成實體地址,若還是查詢不到,則需要缺頁處理,在磁碟中查詢,並將新的頁更新入記憶體中。

7.4 TLB與四級頁表支援下的VA到PA的變換

36位的VPN被分成4個9位的片,每個片被用做到一個頁表的偏移量。CR3暫存器包含L1頁表的實體地址。VPN1提供一個L1 PET的偏移量,這個PTE包含L2頁表的基地址,VPN2再提供一個偏移量,以此類推。
多級頁表 多級頁表的地址翻譯(這裡借用一下老師的圖)

7.5 三級Cache支援下的實體記憶體訪問

實體地址拆分為CT(標記),CI(組索引),CO(塊偏移),依據組索引,找到對應的組,在依據標記查詢是否存在且是否可訪問,最後根據塊偏移找到塊,若沒有找到則向下一級快取記憶體中查詢

7.6 hello程序fork時的記憶體對映

建立當前程序的mm_struct,vm_area_struct和頁表的原樣副本
兩個程序的每個頁面都標記為只讀頁面
兩個程序的每個vm_area_struct都標記為私有,這樣就只能在寫入時複製

7.7 hello程序execve時的記憶體對映

刪除已存在的使用者區域
建立新的私有區域(.malloc,.data,.bss,.text)
建立新的共享區域(libc.so.data,libc.so.text)
設定PC,指向程式碼的入口點

7.8 缺頁故障與缺頁中斷處理

1.第一種情況:缺失發生時,相關的頁已經被載入進記憶體,但是沒有向MMU註冊的情況。作業系統只需要在MMU中註冊相關頁對應的實體地址即可。
2.第二種情況:指相關的頁在頁缺失發生時未被載入進記憶體的情況。這時作業系統需要:尋找到一個空閒的頁。或者把另外一個使用中的頁寫到磁碟上(如果其在最後一次寫入後發生了變化的話),並登出在MMU內的記錄;將資料讀入被選定的頁;向MMU註冊該頁。

7.9動態儲存分配管理

動態記憶體分配器維護這一個程序虛擬記憶體區域,稱為堆
堆
(感謝老師)
顯示分配器主要方法有隱式空閒連結串列,顯示空閒連結串列
連結串列
(再次感謝老師)
由於顯示空閒連結串列可利用空閒塊記錄資料結構,所以更加通用

7.10本章小結

主要表述了一個地址的產生,經過各種翻譯,最後返回需要的資料,包括從虛擬地址到實體地址,再從實體地址找到資料,以及翻譯查詢過程出現缺頁的處理辦法,和維護程序虛擬空間的辦法

第8章 hello的IO管理

8.1 Linux的IO裝置管理方法

裝置的模型化:檔案
檔案的型別:
普通檔案(regular file):包含任意資料的檔案。
目錄(directory):包含一組連結的檔案,每個連結都將一個檔名對映到一個檔案(他還有另一個名字叫做“資料夾”)。
套接字(socket):用來與另一個程序進行跨網路通訊的檔案
命名通道
符號連結
字元和塊裝置

裝置管理:unix io介面

開啟和關閉檔案
讀取和寫入檔案
改變當前檔案的位置

8.2 簡述Unix IO介面及其函式

開啟檔案:open函式,開啟一個已存在的檔案或者建立一個新檔案
int open(char *filename,int flags,mode_t mode);
關閉檔案:close函式,關閉一個已開啟的檔案
int close(int fd);
讀:read函式,執行輸入
寫:write函式,執行輸出
ssize_t read(inf fd,void *buf,size_t n );
ssize_t write(inf fd,const void *buf,size_t n );

8.3 printf的實現分析

printf
其中呼叫的vsprintf函式的作用是格式化。它接受確定輸出格式的格式字串fmt。用格式字串對個數變化的引數進行格式化,產生格式化輸出。Write則將vsprintf的輸出逐個的寫到終端。
從vsprintf生成顯示資訊,到write系統函式,到陷阱-系統呼叫 int 0x80或syscall。
字元顯示驅動子程式:從ASCII到字模庫到顯示vram(儲存每一個點的RGB顏色資訊)。
顯示晶片按照重新整理頻率逐行讀取vram,並通過訊號線向液晶顯示器傳輸每一個點(RGB分量)。

8.4 getchar的實現分析

getchar有一個int型的返回值.當程式呼叫getchar時.程式就等著使用者按鍵.使用者輸入的字元被存放在鍵盤緩衝區中.直到使用者按回車為止(回車字元也放在緩衝區中).當用戶鍵入回車之後,getchar才開始從stdin流中每次讀入一個字元.getchar函式的返回值是使用者輸入的第一個字元的ASCII碼,如出錯返回-1,且將使用者輸入的字元回顯到螢幕.如使用者在按回車之前輸入了不止一個字元,其他字元會保留在鍵盤快取區中,等待後續getchar呼叫讀取.也就是說,後續的getchar呼叫不會等待使用者按鍵,而直接讀取緩衝區中的字元,直到緩衝區中的字元讀完為後,才等待使用者按鍵。
非同步異常-鍵盤中斷的處理:鍵盤中斷處理子程式。接受按鍵掃描碼轉成ascii碼,儲存到系統的鍵盤緩衝區。getchar等呼叫read系統函式,通過系統呼叫讀取按鍵ascii碼,直到接受到回車鍵才返回。

8.5 本章小結

表述了Unix IO介面及其4個函式,簡單瞭解了一下printf,getchar的實現

結論

hello.c一開始說白了就是一堆文字文字,直至經過了預處理、編譯、彙編、與若干其他檔案的連結後終於成為了一個可執行目標檔案hello,此時他已經可以走向linux,在系統中正式開始自己的程式生涯,他被給予上下文成為了程序,在系統中執行並處理訊號,一些有它產生或者他需要的資訊、空間則通過與儲存結構合作,呼叫空間,儲存資訊。而且還會通過I/O裝置與其他程式在進行互動與通訊。
在完成大作業的過程中,回顧了這一學期以來csapp課程許多重要的概念、理解和操作,發現相比於半年前剛剛接觸到深入C程式時對於C有了很多理解,一邊是敬佩和感嘆前人對於計算機系統設計的精妙與複雜,一遍又深覺自己的不足,雖然所謂的深入理解依舊是比較淺的,但是對於編寫程式而言,提供的幫助是顯而易見的。

附件

hello.i hello.c檔案通過預處理後得到的新的程式文字檔案,對於包含檔案,巨集定義以及條件編譯進行了處理;
hello.s hello.i檔案通過編譯後得到的由組合語言編寫的文字檔案,將高階語言轉換成了對應的組合語言;
hello.o hello.s文佳彙編後得到的二進位制檔案,可用於與其他可重定位目標檔案連結形成可執行檔案;
hello 可執行目標檔案,在主機端輸入./hello後可執行程式,完成程式的預期任務;

參考文獻

[1] 林來興. 空間控制技術[M]. 北京:中國宇航出版社,1992:25-42.
[2] 辛希孟. 資訊科技與資訊服務國際研討會論文集:A集[C]. 北京:中國科學出版社,1999.
[3] 趙耀東. 新時代的工業工程師[M/OL]. 臺北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
[4] 諶穎. 空間交會控制理論與方法研究[D]. 哈爾濱:哈爾濱工業大學,1992:8-13.
[5] KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.
[6] CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.
[7] https://blog.csdn.net/dxyinme/article/details/85322271
[8]https://www.cnblogs.com/pianist/p/3315801.html
[9]深入理解計算機系統原書第三版. 機械工業出版社