CPU是Central Processing Unit縮寫, 指的是中央處理器老翘。
CPU的內(nèi)部結(jié)構(gòu)
程序運行流程
- 開發(fā)者用高級語言編寫程序
- 將程序編譯后轉(zhuǎn)變成機器語言的可執(zhí)行文件
- 程序運行時盯蝴,在內(nèi)存中生成可執(zhí)行文件的副本。
- CPU解釋并執(zhí)行程序內(nèi)容
CPU所負責的是解釋和運行最終轉(zhuǎn)換為機器語言的代碼內(nèi)容
CPU和內(nèi)存是有晶體管組成的電子部件代芜,通常稱為IC(Integrated Circuit岸浑,集成電路)侣夷。
從功能上來看最仑,CPU的內(nèi)部由4個部分構(gòu)成缴渊,各部分之間由電流信號相互連通:
- 寄存器:暫存指令赏壹、數(shù)據(jù)等處理對象,可視為內(nèi)存的一種衔沼。
- 控制器:負責把內(nèi)存上的指令蝌借、數(shù)據(jù)等讀入寄存器,并根據(jù)指令的執(zhí)行結(jié)果來控制計算機指蚁。
- 運算器:負責運算從內(nèi)存讀入寄存器的數(shù)據(jù)
- 時鐘:負責發(fā)出CPU開始計時的時鐘信號
內(nèi)存指的是計算機的主存儲器(main memory菩佑,主存),主存通過控制芯片等與 CPU相連凝化,主要負責存儲指令和數(shù)據(jù)稍坯。主存由可讀寫的元素構(gòu)成,每個字節(jié)(1字節(jié)=8位)都帶有一個地址編號搓劫。CPU可通過該地址讀取主存中的指令和數(shù)據(jù)瞧哟,當然也可寫入數(shù)據(jù)。主存中存儲的指令和數(shù)據(jù)會隨著計算機的關(guān)機而自動清除枪向。
程序啟動后勤揩,根據(jù)時鐘信號,控制器會從內(nèi)存中讀取指令和數(shù)據(jù)秘蛔。 通過對指令加以解釋和運行陨亡,運算器會對數(shù)據(jù)進行計算,控制器根據(jù)運算結(jié)果來控制計算機深员。
CPU是寄存器的集合體
CPU的4個構(gòu)成部分中负蠕,開發(fā)者僅需了解寄存器即可,為什么呢辨液?因為程序把寄存器作為對象來描述虐急。
---匯編語言(assembly)
---匯編語言采用助記符(memornic)來編寫程序,每個原本是電氣信號的機器語言指令都會有一個與其相對應(yīng)助記符滔迈。
---助記符通常為指令功能的英文單詞的縮寫
---eax和ebp表示的都是寄存器魄缚,eax是累加寄存器缔御,ebp是基址寄存器慨菱。
---mov和add分別是數(shù)據(jù)的存儲(move)和相加(addition)的縮寫
---使用寄存器來試下數(shù)據(jù)的存儲和加法運算
mov eax, dword ptr [ebp-8] ---將數(shù)值從內(nèi)存復(fù)制到eax
add eax, dword ptr [ebp-0Ch] ---exa的值和內(nèi)存的數(shù)值相加
mov dword ptr [ebp-4], eax ---將exa的數(shù)值存儲到內(nèi)存中
匯編語言和機器語言基本上是一一對應(yīng)的蜂奸,這一點和C碑宴、Java等高級編程語言有很大不同紊浩,這也是使用程序轉(zhuǎn)化成機器語言的過程何吝。
- 匯編:將匯編語言編寫的程序轉(zhuǎn)化成機器語言的過程
- 反匯編:機器語言程序轉(zhuǎn)化成匯編語言的過程
機器語言級別的程序是通過寄存器來處理的忆某,也就是說宏怔,在開發(fā)者看來“CPU是寄存器的集合體”奏路。
匯編語言是80385以上所使用的語言畴椰,eax和ebp是CPU內(nèi)部的寄存器的名稱。內(nèi)存的存儲場所通過地址編號來區(qū)別鸽粉,而寄存器的種類則是通過名字來區(qū)別斜脂。
不同類型的CPU,其內(nèi)部寄存器的數(shù)量触机、種類帚戳、寄存器存儲的數(shù)值范圍都是不同的。不過儡首,根據(jù)功能的不同可將寄存器大致劃分為8類:
寄存器中存儲的內(nèi)容即可以是指令也可以是數(shù)據(jù)
- 用于運算的數(shù)值:累計寄存器
- 表示內(nèi)存地址的數(shù)值:基址寄存器和變址寄存器
數(shù)據(jù)種類不同片任,存儲該數(shù)值的寄存器也不同。CPU中每個寄存器的功能都是不同的蔬胯。用于運算的數(shù)值放在累加寄存器中存儲对供,表示內(nèi)存地址的數(shù)值則放在基址寄存器和變址寄存器中存儲。
對程序員來說氛濒,CPU是什么呢产场?
對程序員來說,CPU是具有各種功能的寄存器的集合體泼橘。其中程序計數(shù)器涝动、累加寄存器、標志寄存器炬灭、指令寄存器醋粟、棧寄存器都只有一個,其他寄存器一般會有多個重归。
決定程序流程的程序計數(shù)器
程序是如何按照流程來運行的呢米愿?
程序?qū)崿F(xiàn):將123和456兩個數(shù)值相加,并將結(jié)果輸出到顯示器鼻吮。
用戶發(fā)出啟動程序的指示后育苟,Windows等操作系統(tǒng)會把硬盤中剛保存的程序復(fù)制到內(nèi)存中。存儲指令和數(shù)據(jù)的內(nèi)存椎木,是通過地址來劃分的违柏。由于使用機器語言難以清晰地表明各地址存儲的內(nèi)容。實際上香椎,一個命令和數(shù)據(jù)通常被存儲在多個地址上漱竖,但為了便于說明,上圖把指令畜伐、數(shù)據(jù)分配到一個地址中馍惹。
地址0100
是程序運行的開始位置,Windows等操作系統(tǒng)把程序從硬盤復(fù)制到內(nèi)存后,會將程序計數(shù)器(CPU寄存器的一種)設(shè)定為0100
万矾,然后程序便開始運行悼吱。
CPU每執(zhí)行一個指令,程序計數(shù)器的值就會自動加1良狈。例如后添,CPU執(zhí)行0100
地址的指令后,程序計數(shù)器的值就會編程0101
们颜,當執(zhí)行的指令占據(jù)多個內(nèi)存地址時吕朵,增加與指令長度響應(yīng)的數(shù)值。然后窥突,CPU的控制器就會參照程序計數(shù)器的數(shù)值努溃,從內(nèi)存中讀取命令并執(zhí)行。也就是說阻问,程序計數(shù)器決定著程序的流程梧税。
條件分支和循環(huán)機制
程序的流程分為順序執(zhí)行、條件分支称近、循環(huán)3種第队。
- 順序執(zhí)行:按照地址內(nèi)容的順序執(zhí)行指令
- 條件分支:根據(jù)條件執(zhí)行任意地址的指令
- 循環(huán):重復(fù)執(zhí)行同一地址的指令
順序執(zhí)行的情況比較簡單,每執(zhí)行一個指令程序計數(shù)器的值就自動加1刨秆。但若程序中存在條件分支和循環(huán)凳谦,機器語言的指令就可將程序計數(shù)器的值設(shè)定為任意地址。這樣一來衡未,程序便可以返回到上一個地址來重復(fù)執(zhí)行同一個指令尸执,或跳轉(zhuǎn)到任意地址。
示例:以條件分支為例缓醋,來具體說明循環(huán)時程序計數(shù)器的數(shù)值設(shè)定機制也是一樣的
程序?qū)崿F(xiàn):把內(nèi)存中存儲的數(shù)值123的絕對值輸出到顯示其的程序的內(nèi)存狀態(tài)
程序運行的開始位置是0100地址如失,隨著順序計數(shù)器數(shù)值的增加,當?shù)竭_0102地址時送粱,如果累計寄存器的值是正數(shù)則執(zhí)行跳轉(zhuǎn)指令(jump指令)跳轉(zhuǎn)到0104地址褪贵。此時,由于累加寄存器的值是123為正數(shù)抗俄,因此0103地址的指令被跳過脆丁,程序流程直接跳轉(zhuǎn)到0104地址。也就是說“跳轉(zhuǎn)到0104地址”這個指令間接執(zhí)行了“將程序計數(shù)器設(shè)定成0104”這個操作动雹。
條件分支和循環(huán)中使用的跳轉(zhuǎn)指令(jump指令)偎快,會參照當前執(zhí)行的運算結(jié)果來判斷是否跳轉(zhuǎn)。
標志寄存器洽胶,無論當前累加寄存器的運算結(jié)果是負數(shù)、0、正數(shù)姊氓,標志寄存器都會將其保存丐怯,同時也負責存放溢出、奇偶校驗的結(jié)果翔横。
- 溢出(overflow):指運算的結(jié)果超出了寄存器的長度范圍
- 奇偶校驗(parity check):指檢查運算結(jié)果的值是偶數(shù)還是奇數(shù)
CPU在進行運算時读跷,標志寄存器的數(shù)值會根據(jù)運算結(jié)果自動設(shè)定。條件分支在跳轉(zhuǎn)指令前會進行比較運算禾唁。置于是否執(zhí)行跳轉(zhuǎn)指令效览,則由CPU在參考標志寄存器的數(shù)值后進行判斷。運算結(jié)果的正荡短、0丐枉、負三種狀態(tài)由標志寄存器的三個位表示。
CPU執(zhí)行比較的機制很有意思掘托,因此請務(wù)必牢記瘦锹。
例如,假設(shè)要比較累加寄存器中存儲的x
值和通用寄存器中存儲的y
值闪盔,執(zhí)行比較的指令后弯院,CPU的運算裝置就會在內(nèi)部進行x-y
的減法運算。而無論減法運算的結(jié)果是整數(shù)泪掀、0听绳、負數(shù),都會保存到標志寄存器中异赫。結(jié)果為正表示x
比y
大椅挣,零表示x
和y
相等,負表示x
比y
小祝辣。程序中的比較指令贴妻,就是在CPU內(nèi)部做減法運算。
函數(shù)的調(diào)用機制
哪怕是高級語言編寫的程序蝙斜,函數(shù)調(diào)用處理也是通過把程序計數(shù)器的值設(shè)定函數(shù)的存儲地址來實現(xiàn)的名惩。不過,與條件分支孕荠、循環(huán)的機制有所不同娩鹉,因為單純的跳轉(zhuǎn)指令無法實現(xiàn)函數(shù)的調(diào)用。函數(shù)調(diào)用需在完成函數(shù)內(nèi)部的處理后稚伍,處理流程再返回到函數(shù)調(diào)入點(函數(shù)調(diào)用指令的下一個地址)弯予。因此,如果只是跳轉(zhuǎn)到函數(shù)的入口地址个曙,處理流程就不知道應(yīng)該返回到那里了锈嫩。
示例:
圖中地址
是將C語言編譯成機器語言后運行時的地址,由于1行C語言程序在編譯后通常會編程多行機器語言,所以地址是離散的呼寸。
給變量a
和b
分別代入123
和456
后艳汽,將其賦值給參數(shù)(parameter)來調(diào)用MyFunc()
函數(shù)的C語言程序。
通過跳轉(zhuǎn)指令把程序計數(shù)器的值設(shè)定成 0260 也可實現(xiàn)調(diào)用 MyFuc()
函數(shù)对雪。函數(shù)的調(diào)用原點(地址0132)和被調(diào)用函數(shù)(地址0260)之間的數(shù)據(jù)傳遞河狐,可以通過內(nèi)存或寄存器來實現(xiàn)。不過當函數(shù)處理進行到最后的0354地址時瑟捣,我們知道應(yīng)該將程序計數(shù)器的值設(shè)定成函數(shù)調(diào)用過后要執(zhí)行的0154地址馋艺,但實際上這一操作根本無法實現(xiàn)。那么迈套,怎么辦才好呢捐祠?
機器語言的call
指令和return
指令能夠解決這個問題,函數(shù)調(diào)用使用的是call
指令交汤,而不是跳轉(zhuǎn)jump
指令雏赦。在函數(shù)的入口地址設(shè)定到程序計數(shù)器之前,call
指令揮把調(diào)用函數(shù)后要執(zhí)行的指令地址存儲在名為棧(stack)的主存內(nèi)芙扎。函數(shù)處理完畢后星岗,再通過函數(shù)的出口來執(zhí)行return
命令。return
命令的功能是把保存在棧中的地址設(shè)定到程序計數(shù)器中戒洼。
MyFunc()
函數(shù)被調(diào)用之前俏橘,0154地址保存在棧中。MyFunc()
的處理完畢后圈浇,棧中的0154地址就會被讀取出來寥掐,然后再被設(shè)定到程序計數(shù)器中。
在編譯高級編程語言的程序后磷蜀,函數(shù)調(diào)用的處理就會轉(zhuǎn)換成call
指令召耘,函數(shù)結(jié)束的處理則會轉(zhuǎn)換成return
指令。這樣一來褐隆,程序的運行也就變得非常流暢污它。
注:棧(stack)本來是“干草堆積如山”的意思。在程序領(lǐng)域表示不斷地存儲各種數(shù)據(jù)的內(nèi)存區(qū)域庶弃。函數(shù)調(diào)用后之所以能正確地返回調(diào)用前的地址衫贬,就是棧的功勞。
通過地址和索引實現(xiàn)數(shù)組
通過基址寄存器和變址寄存器歇攻,可以對主內(nèi)存上特定區(qū)域進行劃分固惯,從而實現(xiàn)類似數(shù)組的操作。
首先使用十六進制數(shù)將計算機內(nèi)存上00000000
~FFFFFFFF
的地址劃分出來缴守,凡是該范圍的內(nèi)存區(qū)域葬毫,只要有一個32位的寄存器镇辉,即可查看全部的內(nèi)存地址。但如果想要像數(shù)組那樣分割特定的內(nèi)存區(qū)域以達到連續(xù)查看的目的供常,使用基址寄存器和變址寄存器會更方便摊聋。
例如:
查看地址10000000
`1000FFFF`時,可將`10000000`存入基址寄存器栈暇,并使變址寄存器的值在`00000000`0000FFFF
變化。CPU則會把基址寄存器和變址寄存器的值解釋為實際查看的內(nèi)存地址箍镜。變址寄存器的值相當于高級語言中數(shù)組的索引功能源祈。
機器語言指令的主要類型和功能
- 數(shù)據(jù)轉(zhuǎn)送指令:寄存器和內(nèi)存、內(nèi)存核內(nèi)存色迂、寄存器和外圍設(shè)置之間的數(shù)據(jù)讀寫操作
- 運算指令:用累加寄存器執(zhí)行算術(shù)運算香缺、邏輯運算、比較運算歇僧、移位運算
- 跳轉(zhuǎn)指令:實現(xiàn)條件分支图张、循環(huán)、強制跳轉(zhuǎn)等
- call/return指令:函數(shù)的調(diào)用/返回調(diào)用前的地址