當前位置:
首頁 > 最新 > 深入理解計算機系統——Hello World 是如何運行的

深入理解計算機系統——Hello World 是如何運行的

1、計算機系統

我們知道計算機系統是由硬體和軟體組成的。它們共同工作來運行應用程序。雖然系統的實現方式隨著時間不斷變化,但是系統內在的概念卻沒有改變。所有計算機系統都有相似的硬體和軟體組件,它們執行這相似的功能,我們只有深入了解這些組件是如何工作的,以及這些組件是如何影響程序的正確性和性能的,才能寫出高質量的代碼。

2、萬能程序大法----Hello World

#include

int main()

{

printf("Hello World
");

return 0;//c標準規定建議main函數返回值為int

}

這段代碼不用多說,就是一個C語言的Hello World,程序的執行結果是列印 「Hello World」。

3、信息的表示

我們將上面的 Hello World 程序保存在一個 hello.c 的文件中,那麼它是怎麼存儲在文件中的呢?實際上它是以位元組序列的方式存儲在文件中。

什麼是位元組?一個位元組由8個位組成,而一個位是由值0和1組成。也就是說 hello.c 源程序是由值0和1組成的位序列。

大部分的現代系統都是用 ASCII 碼構成,這種方式實際上就是用一個唯一的單位元組大小的整數來表示每個字元。下面我們給出 hello.c 程序的 ASCII 碼錶示:

左邊是文件對應的16進位代碼,右邊是我們的源程序,例如:第一個字元「#」的 ASCII 值是0x23。需要特別注意一下:每個文本行都以一個看不見的換行符『
』結束的。第2行中有2個連續的0x0D 0x0A ,這是windows中特有的「換行符
」 ,在linux中的是「換行符
」。像hello.c文件這樣只由 ASCII 碼組成的文件叫做個「文本文件」,其他所有文件都叫「二進位文件」。

系統中所有的信息都是由位+上下文構成。

包括磁碟文件、存儲器中的程序,存儲器中存放的用戶數據以及網路上傳送的數據都是由一串位表示。而區分不同數據對象的唯一方法就是我們讀到這些對象時的上下文。比如在不同的上下文中,一個同樣的位元組序列可能表示一個整數、浮點數、字元串或者機器指令。

作為程序員,我們需要了解數字的機器表示方式,因為它們與實際的整數和實數是不同的。它們是對真值的有限近視值,有時候會有意想不到的行為表現。這個後面我們會詳細講解。

4、程序的編譯

hello 程序的生命周期是從一個高級 C 語言程序開始的,因為這種形式能被人讀懂。然而,計算機系統是讀不懂高級語言的。為了在系統上運行 hello.c 程序,每條 C 語句都必須要被其他程序轉化為一系列的低級機器語言指令。

一般來說,要將 hello.c 變成一個可執行的目標程序,必須要經過 預處理器、編譯器、彙編器和鏈接器 的處理。如下:

預處理器、編譯器、彙編器和鏈接器 一起構成了編譯系統,下面對每個步驟分別進行解析:

、預處理階段:預處理器 cpp 根據以字元 # 開頭的命令,修改原始的 C 程序,比如 Hello.c 中第一行 #include 命令告訴預處理器讀取系統文件 stdio.h 的內容,並把它直接插入到程序中。結果就得到另一個 C 程序,通常是以 .i 作為文件擴展名。

、編譯階段:編譯器 ccl 將文本文件 hello.i 翻譯成文本文件 hello.s,它包含一個彙編語言程序,彙編語言程序中的每條語句都以一種標準的文本格式確切的描述一條低級機器語言指令。彙編語言能為不同高級語言的不同編譯器提供通用的輸出語言。

、彙編階段:彙編器 as 將hello.s 翻譯成機器語言指令,把這些指令打包成一種叫做可重定位目標程序的格式,並將結果保存在目標文件 hello.o 中,hello.o 文件是一個二進位文件,它的位元組編碼是機器預言指令而不是字元。如果我們用文本編輯器打開 hello.o 文件,將會是一堆亂碼。

、鏈接階段:在 hello.c 程序中,我們看到程序調用了 printf 函數,它是每個 C 編譯器都會提供的標準 C 庫中的一個函數。printf 函數存在於一個名為 printf.o 的單獨的預編譯好了的目標文件中,而這個文件必須以某種方式合併到我們的 hello.o 程序中。鏈接器 ld 就是負責處理這種合併,結果就得到一個 hello 文件,它是一個可執行目標程序,可以被載入到內存中,由系統運行。

這裡我做一下驗證,我在 Linux 系統上創建 hello.c 程序,然後依次執行上面的步驟:

預處理:

gcc -E hello.c -o hello.i

然後查看 hello.i

編譯階段:

gcc -S hello.i

然後查看 hello.s

上面截圖的是一個彙編程序

5、程序的運行

經過上面程序的編譯,hello.c 源程序已經被編譯成了可執行目標文件 hello,並存放在磁碟上,那麼如何運行呢?

a、系統的硬體組成

為了理解運行 hello 程序時發生了什麼,我們先要了解一個典型系統的硬體組織。如下圖:

我們現在不需要對這張圖有很深入的理解,後面會詳細進行介紹。現在先簡單的認識一下下面幾個主要部件:

匯流排:貫穿整個系統的一組電子管道,通常被設計成用來傳送定長的位元組塊,也就是字。字的大小與系統相關,比如在32位操作系統當中,一個字是4個位元組。

I/O設備:輸入/輸出(I/O)設備是系統與外部世界聯繫通道,上圖有4個I/O設備。作為用戶輸入的鍵盤和滑鼠,作為用戶輸出的顯示器,以及用於長期存儲數據和程序的磁碟。每一個I/O設備都通過一個控制器或者適配器與I/O匯流排相連。控制器是置於I/O設備本身的或者系統的主印刷電路板(通常稱為主板)上的晶元組,而適配器則是一塊插在主板插槽上的卡。無論如何,它們的功能都是在 I/O 匯流排和 I/O 設備之間傳遞信息。

主存:它是計算機中的一個臨時存儲設備,在處理器執行程序的時候,用來存放程序和程序處理的數據。物理上來說,主存是由一組動態隨機存取存儲器(DRAM)組成的,邏輯上來說,它是一個線性的位元組數組,每一個位元組都有唯一的地址(即數組索引)。

處理器:全稱中央處理器(CPU),是解釋(或執行)存儲在主存中指令的引擎。處理器的核心是一個字長的存儲設備(或寄存器),簡稱程序計數器(PC),在任何時刻,它都會指向主存中的某條機器指令(即含有該條指令的地址)。從系統通電到斷點,處理器一直在不斷的執行程序計數器所指向指令,再更新程序計數器,使其指向下一條指令。處理器所做的操作是圍繞主存、寄存器文件以及算術/邏輯單元(ALU)進行的,寄存器文件是一個小的存儲設備,由一些1字長的寄存器組成,每個寄存器都有唯一的名字。ALU則計算新的數據和地址值。

CPU 在指令的要求下會做如下操作:

、載入:把一個位元組或者一個字從主存複製到寄存器,以覆蓋寄存器原來的內容

、存儲:把一個位元組或者一個字從寄存器複製到主存的某個位置,以覆蓋這個位置上原來的內容

、操作:把兩個寄存器的內容複製到 ALU,ALU 對這兩個字做算術操作,並把結果存放到一個寄存器中,以覆蓋寄存器原來的內容

、跳轉:從指令本身中抽取一個字,並將這個字複製到程序計數器(PC)中,以覆蓋PC中原來的內容。

處理器當中提到的是指令集結構的簡單實現,不過實際上現代處理器使用了非常複雜的機制來加速程序的運行。我們可以這樣去區分指令集機構以及微體系結構,指令集結構描述的是每條機器代碼指令的效果,而微體系結構描述的是處理器實際上是如何實現的,類似於JAVA虛擬機與JAVA虛擬機實現的關係。

b、運行 Hello World 程序

前面簡單的介紹了系統的硬體組成和操作,那麼接下來介紹我們運行程序時到底發生了什麼。

想要在 Linux 系統中運行該可執行程序,我們要將它的文件名輸入到稱為外殼(shell)的應用程序中,外殼是一個命令行解釋器,它輸出一個提示符,等待你輸入一個命令,然後執行這個命令。如果該命令行的第一個單詞不是一個內置的外殼命令,那麼外殼就會假設這是一個可執行文件的名字,它將載入並運行這個文件。

初始時,外殼程序執行它的指令,等待我們輸入一個命令。當我們在鍵盤上輸入字元串"./hello"後,外殼程序將字元逐一讀入到寄存器中,再把它放入到存儲器中,如下圖:

PS:為什麼要輸入「./hello」來執行,對於Linux系統有一定了解的人,可能知道這是運行命令的一種方法。

當我們在鍵盤上敲回車鍵的時候,外殼程序知道我們已經結束了命令的輸入。然後外殼執行一系列指令來載入可執行的 hello 文件,將 hello 目標文件中的代碼和數據從磁碟複製到主存。數據包括最終會被輸出的字元串「Hello World
」,一旦目標文件中的代碼和數據被載入到主存,處理器就開始執行 hello 程序的 main 程序中的機器語言指令。這些指令將「Hello World
」 字元串中的位元組從主存複製到寄存器文件,再從寄存器文件中複製到顯示設備,最終顯示在屏幕上。

6、 本章總結

、出現的名詞解釋:

位:"位(bit)"是電子計算機中最小的數據單位。每一位的狀態只能是0或1。

位元組:8個二進位位構成1個"位元組(Byte)",它是存儲空間的基本計量單位。1個位元組可以儲存1個英文字母或者半個漢字,換句話說,1個漢字佔據2個位元組的存儲空間。

字:"字"由若干個位元組構成,字的位數叫做字長,不同檔次的機器有不同的字長。例如一台8位機,它的1個字就等於1個位元組,字長為8位。如果是一台16位機,那麼,它的1個字就由2個位元組構成,字長為16位。在32位操作系統當中,一個字是4個位元組,字是計算機進行數據處理和運算的單位。

ASCII:American Standard Code for Information Interchange,美國信息交換標準代碼。注意不是ASCⅡ(羅馬數字2),使用指定的7 位或8 位二進位數組合來表示128 或256 種可能的字元。標準ASCII 碼也叫基礎ASCII碼,使用7 位二進位數(剩下的1位二進位為0)來表示所有的大寫和小寫字母,數字0 到9、標點符號, 以及在美式英語中使用的特殊控制字元。

文本文件和二進位文件:

文本文件是指以ASCII碼方式(也稱文本方式)存儲的文件,後面基於 utf-8 編碼的文本文件,utf-8是能夠向後兼容ASCII,即相同的ASCII文本文件和UTF-8文本文件完全一致。它是一種典型的順序文件,其文件的邏輯結構又屬於流式文件。

二進位文件:是基於值編碼的文件,你可以根據具體應用,指定某個值(可以看作是自定義編碼)。

、內容總結

計算機是由軟體與硬體組成的,而硬體又包括了匯流排、I/O設備、主存以及處理器,其中信息是由位以及上下文表示的,而信息則是從I/O設備以位的形式通過匯流排進入主存,然後由處理器從主存將信息取出處理。

一個程序的執行,是經歷了預處理器、編譯器、彙編器以及鏈接器的處理之後,才最終成為可執行的文件。

如需相關更多資料可以上51Testing軟體測試網尋找。

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 51軟體測試網 的精彩文章:

蘋果發布會後的五大質疑,你還敢買嗎?

TAG:51軟體測試網 |