計算機程序是怎樣運行的

<h1>
    <span class="link_title"><a href="/dl0914791011/article/details/23478469">
    計算機程序是怎樣運行的            
    </a></span>
</h1>

關於《深入理解計算機系統

“這本書的中譯名爲深入理解計算機系統,我非常,十分,以及百分之一百二十地不滿意。我這麼說的原因在於這個譯法完全扭曲了書的本意。如果直譯原書名,應該是類似於以程序員的視角理解計算機系統,何來深入二字。可能在國內編輯看來,這是講系統的,用C和彙編語言的,因此很深入,但我認爲這隻能說明國內技術氛圍的淺薄。因爲事實上,這是一本入門級別的書,這本書其實並不深入,它談論的內容還是相對比較淺的。但不代表淺薄,寫一本面向初學者的好書往往是非常困難的,因此無論是SICP還是CSAPP,它的作者都是頂尖學府的教授,結合多年教學經驗而寫出來的。

CMU把這本書作爲“Introduction to Computer System”課程的教材,是面向計算機專業低年級學生的計算機系統介紹(導論),可能這些學生只是剛剛瞭解如何使用一門高級語言——Java進行編程,對於計算機系統的工作方式等話題可謂一點都沒有接觸過,而CSAPP對讀者的背景也只要求是一些編程經驗而已。這本書的話題覆蓋面很廣,從計算機的基本組成,二進制數據表示方式,到機器級別的指令,CPU工作方式,存儲結構和優化,操作系統的虛擬內存管理,程序運行方式,I/O,網絡、到(較底層)程序性能優化和並行程序開發等等。所以,它其實覆蓋了計算機組成原理操作系統等許多課程的內容,其中的許多話題都能再次展開,繼續深入,都能再變成一本,甚至N本經典。事實上,在高年級的計算機專業課程設置中,都會有更加縱向的內容出現。”                                                                                     ——摘自Jeffrey Zhao博文

老趙的這一番話,深深的觸動了我,確實,這本書用怎麼說呢,並不是深入,而是涉及的知識比較廣,但又都是廣大程序猿不得不知道的知識,下面我們就來慢慢品嚐這本書吧。工作之餘,學習學習,總是好的。言歸正傳,接下來,享讀《Computer Systems: A Programmer’s Perspective》的中hello world程序都幹了些啥。

 

1.信息在計算機的中表示

當我們輸入以下程序,編譯運行,計算機從屏幕輸出hello, world。整個過程計算機都怎麼運作的呢?

#include <stdio.h>

int main()

{

printf("hello, world\n");

}

我們知道,信息在計算機中都是用01表示的。計算機通過這些位信息以及上下文來解讀這些0/1。也即:計算機中的信息=+上下文。

我們輸入的hello程序就是由01組成的序列,將這些位8位組織成一個字節,每個字節用來表示一個文本字符。ASCII碼給出了一種字符與數字的一一對應關係。

hello, world程序以字節方式存放於文件中,如下圖所示。其每個字符對應一個數字,具體可參考ASCII碼錶。

1 Hello world程序的ASCII碼錶示

2.將程序翻譯成機器可讀的格式

因爲我們輸入的hello, world程序是人可讀的,機器並不能直接識別它們。我們需要把這些文字翻譯成機器可執行的二進制文件。這一部分的工作是由編譯系統完成的。編譯系統由預處理器、編譯器、彙編器、連接器四部分組成。以hello, world程序爲例,各部分共同完成將源文件編譯成二進制可執行文件。各個部分完成的具體工作如下:

l 預處理器:根據以#開頭的命令,修改源程序。如根據#include <stdio.h>行,預處理器讀取系統頭文件stdio.h中的內容,代替此行內容。源程序經過預處理後,得到另一個c程序,此程序通常以.i爲後綴保存。

l 編譯器:將預處理後的.i文件轉換成彙編程序。編譯器將不同的高級語言(c語言,C++語言)轉換成嚴格一致的彙編語言格式進行輸出。彙編語言以標準的文本格式確切的描述每機器語言指令。編譯器得到的文件通常以.s爲後綴保存。

l 彙編器:將彙編語言(.s文件)翻譯成機器語言指令,並將這些指令打包成一種可定位目標程序格式。彙編後得到的文件即爲二進制文件,通常以.o爲後綴。

l 鏈接器:hello, world程序中調用過printf函數,它是一個c標準庫裏的函數。Printf函數存放在一個名爲printf.o的單獨預編譯的文件中。而這個文件必須以適當的方式併入到我們的程序中,這個工作由鏈接器完成。將外部的.o文件併入後,得到一個完整的hello, world可執行文件。可執行文件加載到存儲器後,由系統複製執行。

編譯系統

Linux系統上,輸入編譯命令行:

Viidiot>gcc hello.c -o hello

將執行上圖所示的四個步驟,得到可執行二進制文件hello

3.處理器讀取並解釋存儲在存儲器中的指令

Shell:命令行解釋器,爲用戶提供了一隻與系統打交道的方式。它等待用戶的輸入,當用戶輸入一行命令後,shell先判斷它是不是一個shell內置命令,如果不是,shell會假定用戶輸入爲一個可執行文件的名字,從而去加載並執行該文件。因此,當我們通過編譯系統將源文件編譯成可執行二進制文件後,在shell中輸入我們得到的可執行二進制文件名,shell將其從磁盤中加載到存儲器(注:我們的可執行文件是存放在磁盤上的),並通過處理器進行解釋執行,得到最終的結果,輸出到終端(顯示器)上進行顯示。自此,我們的hello, world程序完成了其生命週期。

4.計算機系統硬件結構

爲了弄清楚hello, world運行時,系統究竟發生了什麼,我們先來了解下一個典型的計算機硬件結構。

圖3 典型的計算機硬件構成

CPU:中央處理器   ALU:算術/邏輯運算單元  PC:程序計數器  USB:統一串行接口】

 

下面簡單說一下各個部件在系統中所起的作用。

總線:在各個部件之間傳輸數據。現在的總線寬度一般爲32位或者64位,即一次傳輸的數據爲4字節或者8字節。

I/O設備:IO設備是系統與外界通信的通道,如鼠標,鍵盤,顯示器都是典型的IO設備。

主存儲器:簡稱主存,是處理器執行程序時用於臨時存放程序及其數據。主存由一組動態隨機存儲器芯片組成。

處理器:解釋執行存儲在主存中的指令。其內部包含一個雙字節程序計數器(PC),任何時候PC中都存放着接下來要執行的機器指令在主存中的地址。

處理器的操作主要是圍繞PCALU、主存來進行運作的。處理器首先從PC所指向的主存存儲單元讀取指令,解釋指令中的位,執行該指令指示的簡單操作,然後更新PC寄存器,使其指向下一條要執行的指令。CPU會執行的操作有:

加載:把一個字節或一個字從主存複製到寄存器,覆蓋掉寄存器中原來的值。

存儲:把一個字節或一個從寄存器複製到主存,並覆蓋主存中原來的值。

操作:把兩個寄存器的內容複製到ALUALU對兩個字做算術運算後存回其中的一個寄存器,該寄存器中原來的值會被覆蓋。

跳轉:從cpu執行的指令抽取一個字的內容存入PC,覆蓋掉原來的值,從而改變下一條要執行的指令,達到跳轉的目的。

在瞭解了一些基本的硬件結構,以及各個部分的作用後,我們再來看看之前的hello, world程序的運行過程。

圖4 加載可執行文件到主存的過程

linux系統下,我們在shell中敲入以下命令

Viidiot>./hello

由於shell沒有內置hello命令,因此shell將我們輸入的hello視爲一個可執行文件,從而通過執行一系列機器指令,將可執行文件hello從磁盤複製到主存,如圖4所示。

注意,如果通過DMA方式加載程序,則不需要通過CPU,而是將hello可執行文件直接從磁盤複製到主存,示意圖如圖5

圖5 DMA方式加載程序到主存

 

可執行程序加載到主存後,cpu就執行hello程序的機器指令,而這些指令完成的工作便是將”hello,world\n”這幾個字符從主存中複製寄存器文件中(register file),再將其從寄存寄文件中複製到顯示設備上進行顯示。過程示意圖如圖6所示。

圖6  cpu執行指令,將 “helloworld\n”從內存複製到顯示設備

至此,helloworld程序的執行過程已經完成。

題外話:

從上面的程序實例我們可以看到,程序花費了大量的時間將數據從一個部件複製到另外一個部件。程序加載時,將hello程序的機器指令從磁盤複製到主存,程序運行時,又將其從主存複製到cpu,最後又從cpu複製到外部顯示器。將根據機械原理,大容量的存儲設備速度比小容量存儲設備慢,快速設備的造價比慢速設備的造價高。對於計算機硬件系統,CPU的速度遠高於主存的速度,而主存的速度遠高於磁盤,不同部件的速度嚴重不對等,從而快的設備的性能沒能得到充分發揮。爲解決各類設備速度不匹配的問題,引入了高速緩存設備來緩解速度匹配問題。如圖7所示,爲加入了高速緩存後的系統部分結構。

高速緩存存儲器

現代計算機爲提高系統性能,一般都加入了多級緩存結構。高速緩存採樣的是靜態隨機存儲器硬件(SRAM)技術,速度快於主存(採樣動態隨機存儲器技術)。如圖8是存儲器結構金字塔,越往上速度越快,造價也更昂貴。

圖8 存儲器金字塔

作者:Viidiot(阿呆)  轉載請保留作者及鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章