乙個程式在計算機中到底是如何執行的?

2021-09-06 07:39:58 字數 2547 閱讀 2705

在《載入記憶體,讓程式執行起來》一節中講到,程式是儲存在硬碟中的,要載入記憶體才能執行,cpu也被設計為只能從記憶體中讀取資料和指令。

對於cpu來說,記憶體僅僅是乙個存放指令和資料的地方,並不能在記憶體中完成計算功能,例如要計算 a = b + c,必須將 a、b、c 都讀取到cpu內部才能進行加法運算。為了了解具體的運算過程,我們不妨先來看一下cpu的結構。

cpu是乙個複雜的計算機部件,它內部又包含很多小零件,如下圖所示:

運算單元是cpu的大腦,負責加減乘除、比較、位移等運算工作,每種運算都有對應的電路支援,速度很快。

暫存器(register)是cpu內部非常小、非常快速的儲存部件,它的容量很有限,對於32位的cpu,每個暫存器一般能儲存32位(4個位元組)的資料,對於64位的cpu,每個暫存器一般能儲存64位(8個位元組)的資料。為了完成各種複雜的功能,現代cpu都內建了幾十個甚至上百個的暫存器,嵌入式系統功能單一,暫存器數量較少。

我們經常聽說多少位的cpu,指的就是暫存器的的位數。現在個人電腦使用的cpu已經進入了64位時代,例如 intel 的 core i3、i5、i7 等。

暫存器在程式的執行過程中至關重要,不可或缺,它們可以用來完成數**算、控制迴圈次數、控制程式的執行流程、標記cpu執行狀態等。例如,eip(extern instruction pointer )暫存器的值是下一條指令的位址,cpu執行完當前指令後,會根據 eip 的值找到下一條指令,改變 eip 的值,就會改變程式的執行流程;cr3 暫存器儲存著當前程序頁目錄的實體地址,切換程序就會改變 cr3 的值,這將在《mmu部件以及對記憶體許可權的控制》中講解;ebp、esp 暫存器用來指向棧的底部和頂部,函式呼叫會改變 ebp 和 esp 的值,這將在《棧的概念以及棧溢位》中講解。

那麼,在cpu內部為什麼又要設定快取呢?雖然記憶體的讀取速度已經很快了,但是和cpu比起來,還是有很大差距的,不是乙個數量級的,如果每次都從記憶體中讀取資料,會嚴重拖慢cpu的執行速度,cpu經常處於等待狀態,無事可做。在cpu內部設定乙個快取,可以將使用頻繁的資料暫時讀取到快取,需要同一位址上的資料時,就不用大老遠地再去訪問記憶體,直接從快取中讀取即可。

大家在購買cpu時,也會經常關心快取容量,例如 intel core i7 3770k 的**快取為 8mb,二級快取為 256kb,一級快取為 32kb。容量越大,cpu越強悍。
快取的容量是有限的,cpu只能從快取中讀取到部分資料,對於使用不是很頻繁的資料,會繞過快取,直接到記憶體中讀取。所以不是每次都能從快取中得到資料,這就是快取的命中率,能夠從快取中讀取就命中,否則就沒命中。關於快取的命中率又是一門學問,哪些資料保留在快取,哪些資料不保留,都有複雜的演算法。

要想讓cpu工作,必須借助特定的指令,例如 add 用於加法運算,sub 用於除法運算,cmp 用於比較兩個數的大小,這稱為cpu的指令集(instruction set)。我們的c語言**最終也會編譯成一條一條的cpu指令。不同型號的cpu支援的指令集會有所差異,但絕大部分是相同的。

我們以c語言中的加法為例來演示cpu指令的使用。假設有下面的c語言**:

int a = 0x14, b = 0xae, c;

c = a + b;

在vs2010 debug模式下生成的cpu指令為:

mov  ptr[a], 0x14

mov  ptr[b], 0xae

mov  eax, ptr[a]

add  eax, ptr[b]

mov  ptr[c], eax

mov 和 add 都是cpu指令:

1) mov 用來將乙個數值移動到乙個儲存位置。這個數值可以是乙個常數,也可以在記憶體或者暫存器上;這個儲存位置可以是暫存器或者記憶體。

第一條指令中,ptr[a]表示變數 a 的位址,0x14是乙個數值,mov ptr[a], 0x14表示把數值 0x14 移動到 ptr[a] 指向的記憶體,也就是給變數 a 賦值。第二條指令與此類似。

第三條指令中,eax是暫存器的名字,該暫存器常用在加法運算中,用來儲存某個加數或運算結果,mov eax, ptr[a]表示把變數 a 的值移動到暫存器 eax 中。

第五條指令表示把暫存器 eax 的值移動到變數 c 中,此時 exa 中的值為 a、b 相加的和。

2) add 用來將兩個數值相加,這兩個數值可以在暫存器或者記憶體中,add 會將相加的結果放在第乙個數所在的位置。第四條指令add  eax, ptr[b]表示把 eax 和 ptr[a] 中的數值相加,並把結果放在 eax 中。

總起來講:第一二條指令給變數 a、b 賦值,第三四條指令完成加法運算,第五條指令將運算結果賦值給變數 c。

實際上,上面的**是組合語言,不是cpu指令,組合語言還要經過簡單的轉換才能成為cpu指令;為了更加容易地說明問題,這些語句也沒有嚴格遵守彙編的語法。有興趣的同學可以自行學習組合語言,這裡不再展開講解。
本節我們講解了cpu的簡單構造以及cpu指令,重點是讓大家認識暫存器這個小而快速的儲存部件,它在程式執行過程中起著至關重要的作用,cpu就是用它來記錄程式的執行狀態,然後根據它的值再決定下一步的操作。

**:

字元在計算機中是如何表示的?

如果計算機只儲存二進位制資料,那麼它如何表示字元呢?計算機使用的是字符集,將字元對映為整數。早期,字符集只用 8 位表示。即使是現在,在字元模式 如 ms dos 下執行時,ibm 相容微機使用的還是 ascii 讀為 askey 字符集。ascii 是美國標準資訊交換碼 ametican stan...

負數在計算機中如何表示?

負數在計算機中如何表示?舉例來說,8在計算機中表示為二進位制的1000,那麼 8怎麼表示呢?很容易想到,可以將乙個二進位制位 bit 專門規定為符號位,它等於0時就表示正數,等於1時就表示負數。比如,在8位機中,規定每個位元組的最高位為符號位。那麼,8就是00001000,而 8則是10001000...

負數在計算機中如何表示?

為什麼要使用2的補碼 two s complement 形式儲存負數?反碼舉例來說 8在計算機中表示為二進位制的1000,那麼 8怎麼表示呢?可以將乙個二進位制最高位 bit 專門規定為符號位,它等於0時就表示正數,等於1時就表示負數。比如,在8位機中,規定每個位元組的最高位為符號位。那麼,8就是0...