1. 程式人生 > >第一章 計算機系統漫遊(從helloworld的編譯到)

第一章 計算機系統漫遊(從helloworld的編譯到)

1.1資訊就是位(bit)+上下文

hello world程式:

#include <stdio.h>

int main()
{
 	printf("hello,world\n");
 	return 0;
}

通過文字編輯器儲存的hello world程式程式碼檔案稱為源程式,副檔名為.c。檔案中所有字元都是由0和1組成的位(bit)(1byte=8bit)表示,每個英文字母和標點符號都用一個位元組表示(ASCII編碼)。具體如下圖所示。 在這裡插入圖片描述 源程式以位元組序列的方式儲存在檔案中,每個位元組表示一個整數值,對應特定字元。

據此程式我們可以引申一下——計算機世界的所有資訊都是用0、1表示的bit序列。根據上下文的不同,一個同樣的位元組可能表示一個整數、浮點數、字串或者是機器指令。

1.2 程式被其他程式翻譯成不同的格式

系統只能執行打包成可執行目標程式格式的二進位制磁碟檔案。 在Unix系統上,由編譯器驅動程式(GCC)完成從源程式到可執行目標檔案(可執行目標程式)轉換。這一轉換可分為四個階段,分由四個程式完成(前處理器、編譯器、彙編器、聯結器),它們共同組成編譯系統。如下圖: 在這裡插入圖片描述

  • 預處理階段:根據hello程式中的#開頭指令插入特定的內容。#include<stdio.h>命令告訴前處理器讀取系統標頭檔案的stdio.h的內容,並插入到源程式中。
  • 編譯階段:翻譯成組合語言。組合語言是低階機器語言,為不同高階語言的不同編譯器提供通用的輸出語言。
  • 彙編階段:翻譯成機器語言指令(二進位制),指令被打包成可重定位目標程式。
  • 連結階段:呼叫一個名為printf.o的單獨預編譯好的目標檔案,以滿足源程式呼叫printf函式的需要。合併二者。得到最終的可執行目標檔案。

1.4 處理器讀取並解釋可執行目標檔案。

執行命令:

linux> ./hello
hello,world

./是指當前目錄。上述執行的操作在shell程式中,shell是一個命令列直譯器。如果該命令列的第一個單詞不是一個內建的shell命令,shell就會把它當做可執行檔案,載入並執行。 1.4.1系統的硬體組成 典型的系統硬體組成圖: 在這裡插入圖片描述

  • 匯流排:貫穿整個系統的一組電子導管。攜帶位元組資訊在各個部件間傳遞。機器字長(32位,64位)即是匯流排傳送定長位元組塊的位元組數。
  • I/O裝置:示例中包含四個I/O裝置:鍵盤、滑鼠、顯示器、磁碟。它們都通過控制器或者介面卡與I/O匯流排相連。控制器與介面卡的主要是封裝方式不同:控制器是I/O裝置本身或者是主機板上的晶片組。介面卡是插在主機板上的卡;它們負責將資訊傳遞到I/O匯流排。
  • 主存:臨時儲存裝置。處理器執行程式時,用來存放程式和程式處理的資料。物理上:主存是一組動態隨機存取儲存器(DRAM)晶片組成。邏輯上:是一個線性位元組陣列,每個位元組都有陣列索引(稱為地址)。
  • 中央處理器(CPU),簡稱處理器。解釋或執行主存裡的指令引擎。核心是程式計數器(PC),CPU中最重要的暫存器,指向主存的某條機器語言指令的地址。暫存器檔案包含一些單字長(字長取決於匯流排的設計)的暫存器組成。
  • 相關操作: ☆ 載入:從主存複製一個位元組或者一個字(漢字在大部分編碼格式中佔兩個位元組)到暫存器,覆蓋寄器原來的內容。 ☆ 儲存:從暫存器複製一個位元組或者一個字到主存,覆蓋某個位置的內容。與載入互逆。 ☆ 操作:兩個暫存器的內容被複制到ALU(算數/邏輯單元),ALU對兩者做算數運算,把結果存放於一個暫存器中,覆蓋原來內容。 ☆ 跳轉:從指令本身中抽取一個字,並複製到程式計數器中,覆蓋原來的值。 1.4.2執行hello程式
  • 輸入字串時“./hello”時,shell程式將字元逐一讀入暫存器檔案中的暫存器,再搬運到記憶體。如圖:在這裡插入圖片描述
  • 按下回車鍵時,shell程式執行一系列指令載入可執行目標檔案——hello程式。這些指令將hello目標檔案中的程式碼和資料從磁碟複製到主存。利用直接儲存器存取(DMA)技術,資料可以不通過處理器從磁碟直達記憶體。一旦目標檔案被載入至主存,處理器就開始執行main程式中的機器語言指令。這些指令將“hello,world\n"字串的位元組從主存複製到暫存器檔案(載入),再從暫存器檔案中複製到顯示裝置,最終顯示在螢幕上。如圖:在這裡插入圖片描述 至此,hello程式從編譯到執行的生命週期結束。