国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

Linux|Centos|Ubuntu|系統(tǒng)進(jìn)程|Fedora|注冊表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服務(wù)器之家 - 服務(wù)器系統(tǒng) - Linux - Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

2021-06-30 23:27IOT物聯(lián)網(wǎng)小鎮(zhèn)道哥 Linux

Linux 系統(tǒng)中的很多關(guān)于分段、內(nèi)存、寄存器相關(guān)的設(shè)計,都可以在這些書籍中找到基礎(chǔ)支撐。于是乎,我就有了一個想法:是否可以把這些書籍中,與 Linux 系統(tǒng)相關(guān)的內(nèi)容進(jìn)行一次重讀和整理,但絕不是簡單的知識搬運。

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

Linux 從頭學(xué)】是什么

 

這兩年多以來,我的本職工作重心一直是在 x86 Linux 系統(tǒng)這一塊,從驅(qū)動到中間層,再到應(yīng)用層的開發(fā)。

隨著內(nèi)容的不斷擴展,越發(fā)覺得之前很多基礎(chǔ)的東西都差不多忘記了,比如下面這張表(《深入理解 LINUX 內(nèi)核》第 47 頁):

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

這張表描述了 Linux 系統(tǒng)中幾個段描述符信息。

數(shù)據(jù)段和代碼段,仔細(xì)看一下相關(guān)書籍就知道這些描述符代表什么意思,但是:

為什么這幾個段的 Base 地址都是 0x00000000?

為什么 Limit 都是 0xfffff?

為什么它們的 Type 類型和優(yōu)先級 DPL 又各不相同?

如果沒有對 x86 平臺的一些基礎(chǔ)知識的理解,要啃完這本書真的是挺費力氣的!

更要命的是,隨著 Linux 內(nèi)核代碼的體積不斷膨脹,最新的 5.13 版本壓縮檔已經(jīng)是一百多兆了:

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

這么一個龐然大物,如何下手才能真正的學(xué)好 Linux 呢?!

即便是從 Linux 0.11 版本開始,其中的很多代碼看起來也是非常費勁的!

周末在整理一些吃灰的書籍時,發(fā)現(xiàn)幾本以前看過的好書: 王爽的《匯編語言》,李忠的《從實模式到保護(hù)模式》,馬朝暉翻譯的《匯編語言程序設(shè)計》等等。

都是非常-非常-老的書籍,再次翻了一下,真心覺得內(nèi)容寫得真好!

對一些概念、原理、設(shè)計思路的描述,清晰而透徹。

Linux 系統(tǒng)中的很多關(guān)于分段、內(nèi)存、寄存器相關(guān)的設(shè)計,都可以在這些書籍中找到基礎(chǔ)支撐。

于是乎,我就有了一個想法:是否可以把這些書籍中,與 Linux 系統(tǒng)相關(guān)的內(nèi)容進(jìn)行一次重讀和整理,但絕不是簡單的知識搬運。

考慮了一下,大概有下面幾個想法:

  1. 先確定最終目標(biāo)的目標(biāo):學(xué)習(xí) Linux 操作系統(tǒng);
  2. 這幾本書寫的都是匯編語言,以及比較基礎(chǔ)的底層知識。我們會淡化匯編語言部分,把重點放在與 Linux 操作系統(tǒng)有關(guān)聯(lián)的原理部分;
  3. 不會嚴(yán)格按照書中的內(nèi)容、順序來輸出文章,而是把幾本書中內(nèi)容相關(guān)的部分放在一起學(xué)習(xí)、討論;
  4. 有些內(nèi)容,可以與 Linux 2.6 版本中的相關(guān)部分進(jìn)行對比分析,這樣的話在以后學(xué)習(xí) Linux 內(nèi)核部分時,可以找到底層的支撐;
  5. 最后,希望我自己能堅持這個系列,也算是給自己的一個梳理吧。

一句話:以基礎(chǔ)知識為主!

作為開篇第一章,本文將會描述下面這張圖的執(zhí)行步驟:

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

現(xiàn)在就開始吧!

古老的 Intel8086 處理器

 

8086 是 Intel 公司的第一款 16 位處理器,誕生于 1978 年,應(yīng)該比各位小伙伴的年齡都大一些。

在 Intel 公司的所有處理器中,它占有很重要的地位,是整個 Intel 32 位架構(gòu)處理器(IA-32)的開山鼻祖。

那么,問題來了,什么叫 16 位的處理器?

有些人會把處理器的位數(shù)與地址總線的位數(shù)搞混在一起!

我們知道,CPU 在訪問內(nèi)存的時候,是通過地址總線來傳送物理地址的。

8086 CPU 有 20 位的地址線,可以傳送 20 位地址。

每一根地址線都表示一個 bit,那么 20 個 bit 可以表示的最大值就是 2 的 20 次方。

也就是說:最大可以定位到 1M 地址的內(nèi)存,這稱作 CPU 的尋址能力。

但是,8086 處理器卻是 16 位的,因為:

  1. 運算器一次最多可以處理 16 位的數(shù)據(jù);
  2. 寄存器的最大寬度為 16 位;
  3. 寄存器和運算器之間的通路為 16 位;

也就是說:在 8086 處理器的內(nèi)部,能夠一次性處理、傳輸、暫時存儲的最大長度是 16 位,因此,我們說它是 16 位結(jié)構(gòu)的 CPU。

主存儲器是什么?

 

計算機的本質(zhì)就是對數(shù)據(jù)的存儲和處理,那么參與計算的數(shù)據(jù)是從哪里來的呢?那就是一個稱作 存儲器(Storage 或 Memory)的物理器件。

從廣義上來說,只要能存儲數(shù)據(jù)的器件都可以稱作存儲器,比如:硬盤、U盤等。

但是,在計算機內(nèi)部,有一種專門與 CPU 相連接,用來存儲正在執(zhí)行的程序和數(shù)據(jù)的存儲器,一般稱作內(nèi)存儲器或者主存儲器,簡稱:內(nèi)存或主存。

內(nèi)存按照字節(jié)來組織,單次訪問的最小單位是 1 個字節(jié),這是最基本的存儲單元。

每一個存儲單元,也就是一個字節(jié),都對應(yīng)著一個地址,如下圖所示:

 Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

CPU 就通過地址總線來確定:對內(nèi)存中的哪一個存儲單元中的數(shù)據(jù)進(jìn)行訪問。

第 1 個字節(jié)的地址是 0000H,第 2 個字節(jié)的地址是 0001H,后面以此類推。

圖中的這個內(nèi)存,最大存儲單元的地址是 FFFFH,換算成十進(jìn)制就是 65535,因此這個內(nèi)存的容量是 65536 字節(jié),也就是 64 KB。

這里有一個原子操作的問題可以考慮一下。

在 Linux 內(nèi)核代碼中,很多地方使用了原子操作,比如:互斥鎖的實現(xiàn)代碼。

為什么原子操作需要對變量的類型限制為 int 型呢?這就涉及到對內(nèi)存的讀寫操作了。

盡管內(nèi)存的最小組成單位是字節(jié),但是,經(jīng)過精心的設(shè)計和安排,不同位數(shù)的 CPU,能夠按照字節(jié)、字、雙字進(jìn)行訪問。

換句話說,僅通過單次訪問,16 位處理器就能處理 16 位的二進(jìn)制數(shù),32 位處理器就能處理 32 位的二進(jìn)制數(shù)。

寄存器是什么?

 

在 CPU 內(nèi)部,一些都是代表 0 或 1 的電信號,這些二進(jìn)制數(shù)字的一組電信號出現(xiàn)在處理器內(nèi)部線路上,它們是一排高低電平的組合,代表著二進(jìn)制數(shù)中的每一位。

在處理器內(nèi)部,必須用一個稱為寄存器的電路把這些數(shù)據(jù)鎖存起來。

因此,寄存器本質(zhì)上也屬于存儲器的一種。只不過它們位于處理器的內(nèi)部,CPU 訪問寄存器比訪問內(nèi)存的速度更快。

處理器總是很忙的,在它操作的過程中,所有數(shù)據(jù)在寄存器里面只能是臨時存在一小會,然后再被送往別處,這就是為什么它被叫做“寄存器”。

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

8086 中的寄存器都是 16 位的,可以存放 2 個字節(jié),或者說 1 個字。高字節(jié)在前(bit8 ~ bit15),低字節(jié)在后(bit0 ~ bit7)。

8086 中有下面這些寄存器:

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

剛才說了,這些寄存器都是 16 位的。由于需要與以前更古老的處理器兼容,其中的 4 個寄存器:AX、BX、CX、DX 還可以當(dāng)成 2 個 8 位的寄存器來使用。

比如:AX 代表一個 16 位的寄存器,AH、AL 分別代表一個 8 位的寄存器。

  1. mov AX, 5D  表示把 005D 送入 AX 寄存器(16 位) 
  2. mov AL, 5D  表示把 5D 送入 AL 寄存器(8 位) 

三個總線

 

當(dāng)我們啟動一個應(yīng)用程序的時候,這個程序的代碼和數(shù)據(jù)都被加載到物理內(nèi)存中。

CPU 無論是讀取指令,還是操作數(shù)據(jù),都需要與內(nèi)存進(jìn)行信息的交互:

  1. 確定存儲單元的地址(地址信息);
  2. 器件的選擇,讀或?qū)懙拿?控制信息);
  3. 讀或?qū)懙臄?shù)據(jù)(數(shù)據(jù)信息);

在計算機中,有專門連接 CPU 和其他芯片的數(shù)據(jù),稱為總線。

從邏輯上來分類,包括下面 3 種總線:

  • 地址總線:用來確定存儲單元的地址;
  • 控制總線: CPU 對外部期間進(jìn)行控制;
  • 數(shù)據(jù)總線: CPU 與內(nèi)存或其他器件之間傳送數(shù)據(jù);

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

8086 有 20 根地址線,稱作地址總線的寬度,它可以尋址 2 的 20 次方個內(nèi)存單元。

同樣的道理,8086 數(shù)據(jù)總線的寬度是 16,也就是一次性可以傳送 16 bit 的數(shù)據(jù)。

控制總線決定了 CPU 可以對外進(jìn)行多少種控制,決定了 CPU 對外部器件的控制能力。

CPU 如何對內(nèi)存進(jìn)行尋址?

 

在 Linux 2.6 內(nèi)核代碼中,編譯器產(chǎn)生的地址叫做虛擬地址(也稱作:邏輯地址),這個邏輯地址經(jīng)過段轉(zhuǎn)換之后,變成線性地址,線性地址再經(jīng)過分頁轉(zhuǎn)換,就得到最終物理內(nèi)存上的物理地址。

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

還記得文章開頭的那張段描述符的表格嗎?

其中的代碼段和數(shù)據(jù)段描述符的起始地址都是 0x00000000,也就是說: 在數(shù)值上虛擬地址和轉(zhuǎn)換后的線性地址是相等的(稍后就會明白為什么是這樣)。

我們再來看看一下 8086 中更簡單的地址轉(zhuǎn)換。

剛才說到,內(nèi)存是一個線性的存儲器件,CPU 依賴地址來定位每一個存儲單元。

對于 8086 CPU 來說,它有 20 根地址線,可以傳送 20 位地址,達(dá)到 1MB 的尋址能力。

但是 8086 又是 16 位的結(jié)構(gòu),在內(nèi)部一次性處理、傳輸、暫時存儲的地址只有 16 位。

從內(nèi)部結(jié)構(gòu)來看,如果將地址從內(nèi)部簡單的發(fā)出到地址總線上,只能送出 16 位的地址,這樣的話,尋址能力只有 64KB。

那么應(yīng)該怎么才能充分利用 20 根地址線呢?

8086 CPU 采用: 在內(nèi)部使用兩個 16 位地址合成的方法,來形成一個 20 位的物理地址,如下所示:

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

第一個 16 位的地址稱為段地址,第二個 16 位的地址稱為偏移地址。

地址加法器采用下面的這個公式,來“合成”得到一個 20 位的物理地址:

  • 物理地址 = 段地址 x 16 + 偏移地址

例如:我們編寫的程序,在加載到內(nèi)存中之后,放在一個內(nèi)存空間中。

CPU 在執(zhí)行這些指令的時候,把 CS 寄存器當(dāng)做段寄存器,把 IP 寄存器當(dāng)做偏移寄存器,然后計算 CS x 16 + IP 的值,就得到了指令的物理地址。

從以上的描述中可以看出:8086 CPU 似乎是因為寄存器無法直接輸出 20 位的物理地址,不得已才使用這樣的地址合成方式。

其實更本質(zhì)的原因是:8086 CPU 就是想通過 基地址 + 偏移量 的方式來對內(nèi)存進(jìn)行尋址(這里的基地址,就是段地址左移 4 位)。

也就是說,即使 CPU 有能力直接輸出一個 20 位的地址,它仍然可能會采用 基地址 + 偏移量的方式來進(jìn)行內(nèi)存尋址。

想一下:我們在 Linux 系統(tǒng)中編譯一個庫文件的時候,一般都會在編譯選項中添加 -fPIC 選項,表示編譯出來的動態(tài)庫是地址無關(guān)的,在被加載到內(nèi)存時需要被重定位。

而基地址+偏移量的尋址模式,就為重定位提供了底層支撐。

我們是如何控制 CPU 的?

 

CPU 其實是一個很純粹、很呆板的一個東西,它唯一做的事情就是:到 CS:IP 這兩個寄存器指定的內(nèi)存單元中取出一條指令,然后執(zhí)行這條指令:

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

當(dāng)然了,還需要預(yù)先定義一套指令集,在內(nèi)存中的指令區(qū)中,存儲的都必須是合法的指令,否則 CPU 就不認(rèn)識了。

每一條指令都是用某些特定的數(shù)(指令碼)來指示 CPU 進(jìn)行特定的操作。

CPU 認(rèn)識這些指令,一看到這些指令碼,CPU 就知道這個指令碼后面還有幾個字節(jié)的操作數(shù)、需要進(jìn)行什么樣的操作。

例如:指令碼 F4H 表示讓處理器停機,當(dāng) CPU 執(zhí)行這條指令的時候,就停止工作。

(其實這里說 CPU 已經(jīng)有點不準(zhǔn)確了,因為 CPU 是囊括了很多器件的一個整體,也許這里說 CPU 中的執(zhí)行單元會更準(zhǔn)確些。)

另外有一點可以提前說一下:內(nèi)存中的一切都是數(shù)據(jù),至于把其中的哪一部分?jǐn)?shù)據(jù)當(dāng)做指令來執(zhí)行,哪一部分?jǐn)?shù)據(jù)當(dāng)做被指令操作的“變量”,這完全是由操作系統(tǒng)的設(shè)計者來規(guī)劃的。

在 8086 處理器的層面來說,只要是 CS:IP “指向”的內(nèi)存區(qū)域,都被當(dāng)做指令來執(zhí)行。

從以上描述可以看出:在 CPU 中,程序員能夠用指令讀寫的器件只有寄存器,我們可以通過改變寄存器中的內(nèi)容,來實現(xiàn)對 CPU 的控制。

更直白的說就是:我們可以通過改變 CS、IP 寄存器中的內(nèi)容,來控制 CPU 執(zhí)行目標(biāo)指令。

作為一名合格的嵌入式開發(fā)者,大家估計都配置過一些單片機里的寄存器,以達(dá)到一些功能定義、端口復(fù)用的目的,其實這些操作,都可以看做是我們對 CPU 的控制。

如果把 CPU 比作木偶,那么 寄存器就是控制木偶的繩索。

我們再把 CPU 與 工控領(lǐng)域的 PLC 編程進(jìn)行類比一下。

我們在拿到一個新的 PLC 設(shè)備之后,其中只有一個運行時(runtime),這個運行時執(zhí)行的本職工作就是:

  1. 掃描所有的輸入端口,鎖存在輸入映象區(qū);
  2. 執(zhí)行一個運算、控制邏輯,得到一些列輸出信號,鎖存到輸出映象區(qū);
  3. 把輸出映象區(qū)的信號,刷新到輸出端口;

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

在一個全新的 PLC 中,其中第 2 個步驟中需要的運算、控制邏輯可能就不存在。

因此,單單一個 runtime,PLC 是無法完成一件有意義的工作的。

為了讓 PLC 完成一個具體的控制目標(biāo),我們還需要利用 PLC 廠家提供的上位機編程軟件,開發(fā)一個運算、控制邏輯程序,編程語言一般都是梯形圖居多。

當(dāng)這個程序被下載到 PLC 中之后,它就可以控制運行時來做一些有意義的工作了。

我們可以簡單的認(rèn)為:梯形圖就是用來控制 PLC 的運行時。

Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

對于 CPU 來說,想讓它執(zhí)行某個內(nèi)存單元的指令,只要修改寄存器 CS 和 IP 即可。

換句話說:只要對一個程序的內(nèi)存布局足夠的清楚,可以把 CPU 玩弄于股掌之間,讓它執(zhí)行哪里的代碼都可以。

CPU 執(zhí)行指令流程

 

現(xiàn)在我們已經(jīng)明白了地址轉(zhuǎn)換、內(nèi)存的尋址,距離 CPU 執(zhí)行一條指令需要的最小單元還剩下:指令緩沖區(qū)和控制電路。

簡單來說:指令緩沖區(qū)用來緩存從內(nèi)存中讀取的指令,控制電路用來協(xié)調(diào)各種器件對總線等資源的使用。

對于下面這張圖來說,它一共有 4 條指令:

 Linux 從頭學(xué) 01:CPU 是如何執(zhí)行一條指令的

以第一條指令來舉例,它一共經(jīng)過 5 個步驟:

  1. 把 CS:IP 內(nèi)容送入地址加法器,計算得到 20 位的物理地址 20000H;
  2. 控制電路把 20 位的地址,送入到地址總線;
  3. 內(nèi)存中 20000H 單元處的指令 B8 23 01,經(jīng)過數(shù)據(jù)總線被送到指令緩沖區(qū);
  4. 指令偏移寄存器 IP 的值要加 3,指向下一條等待被執(zhí)行的偏移地址(因為指令碼 B8 代表當(dāng)前指令的長度是 3 個字節(jié));
  5. 執(zhí)行指令緩沖區(qū)中的指令: 把數(shù)值 0123H 送入寄存器 AX 中;

以上就是一條指令的執(zhí)行最基本步驟,當(dāng)然,現(xiàn)代處理器的指令執(zhí)行流程,比這里的要復(fù)雜的多得多。

萬丈高樓平地起!

這篇文章,僅僅描述了 CPU 執(zhí)行一條指令所需要的最小知識點。

本文轉(zhuǎn)載自微信公眾號「 IOT物聯(lián)網(wǎng)小鎮(zhèn)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 IOT物聯(lián)網(wǎng)小鎮(zhèn)公眾號。

原文鏈接:https://mp.weixin.qq.com/s/IZ_rDDA7igryWXbuPuq1-g

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: av电影免费观看 | 国产视频一区二区在线 | 中文日韩在线 | 自拍亚洲| 黄色毛片在线视频 | 动漫卡通精品一区二区三区介绍 | 久久久久久久久久久久久大色天下 | 日日夜夜添 | 综合色区| 亚洲精品国产区欧美区在线 | 五月天婷婷社区 | 黄视频网站免费观看 | 欧美日本韩国一区二区 | 婷婷五月色综合 | 国产一级一级国产 | 色女人的天堂 | 成人片免费看 | 欧美综合在线观看 | 99久久成人 | 怡红院成人影院 | 精品中文字幕在线 | 在线视频 亚洲 | 日本中文字幕免费 | 毛片aaa | 91社影院在线观看 | 综合一区 | 日韩av中文字幕在线播放 | 日韩精品一区二区三区在线播放 | 黄网免费看| 久久av网| 欧美日韩中文在线 | 国产成人高清在线 | 中文一区 | 日韩成人在线视频 | 高清在线一区 | 香蕉久久av一区二区三区 | 欧美日韩一区二区三区不卡视频 | 亚洲美女在线视频 | 99国产精品99久久久久久 | 亚洲一区在线免费观看 | 欧美日韩三区 |