程序經過編譯后,變成了可執行的文件,可執行文件主要包括代碼和數據兩部分,代碼是只讀的,數據則是可讀可寫的。
可執行文件由操作系統加載到內存中,交由CPU去執行,現在問題來了,CPU怎么去訪問代碼和數據?,訪問的方式經歷過四個階段:
1.直接訪問
2.段基址+段偏移地址
3.段選擇子+段偏移地址
4.虛擬地址
現代操作系統采用的是虛擬地址,這也是本篇文章闡述的重點,但虛擬地址是由13階段發展而來的,所以也有必要闡述13三種訪問方式。
直接訪問
直接訪問很好理解,程序經過編譯后,生成了可執行文件,編譯器給每行數據和代碼分配了一個唯一的地址,如下圖
可執行文件
如上圖可執行文件中10001024之間的地址,加載到內存后,內存的地址也是10001024,在可執行文件中分配的唯一地址就是內存中的物理地址,這就叫直接訪問,直接定訪問干脆直接,沒有那些彎彎繞。
當時問題也不少,例如同一個可執行文件不能同時執行,它們的物理地址一樣,沖突了,必須一個接一個,還有就是可執行文件的物理地址已經固定了,如果想在其它物理地址運行,必須地重新編譯,生成新的物理地址。
可見直接定位是計算機發展早期的產物,早期沒有那么多的程序要運行,程序都是一個接一個地去執行的,因此早期這種定位比較簡單,直接高效。
段基址+段偏移地址
隨著多任務需求的來臨,現在內存中要并發運行多個程序,雖然采用直接定位把每個不同的程序放在不同的內存段中,勉強可以滿足,但是一個可執行文件不能同時運行多個,另外程序必須在固定的物理地址運行,靈活性大大減弱,調度起來也是非常麻煩,因此CPU設計師和操作系統開發人員發明了段基址+段偏移地址。
Inter 8086處理器就是采用這種定位方式,我們知道可執行文件主要分為數據段和內存段,如下圖
由上圖紅色部分可知,0,4,8就是相對于數據段的偏移地址,0,4,8,12是相對于代碼段的偏移地址。
在可執行文件中,一個段的偏移地址是固定的,無論可執行文件加載到內存的什么位置,這個偏移地址是固定的。
當可執行文件加載到內存時,先在內存中分配一個數據段和代碼段,這兩個段理論上可以不挨著,一般情況下,代碼段和數據段是挨著的,代碼段和數據段在內存中都有一個起始地址,這個起始地址就叫做段基址,這個段基址是放在段寄存器里,例如代碼段基址放在CS寄存器,數據段基址放在DS寄存器,當然還有其他的段例如棧段,棧段剛開始大小為0,隨著程序的運行入棧,出棧,這個棧段在不斷擴展,當然,咋們主要說的是數據段和代碼段,棧段只是簡單帶過。
假設可執行文件被加載到了內存中,如下圖
如上圖所示,代碼段被布局到以0x00600000為起始地址的內存中,數據段被布局到以0x00601000為起始地址的內存中。
當CPU開始執行代碼段的第一條指令時,會將代碼段的起始地址放入到段寄存器中,此時CS代碼段寄存器中存儲的就是0x00600000,然后開始從起始地址處開始執行第一條代碼指令,此時把代碼指令的偏移地址放入到IP寄存器中,IP寄存器存儲的就是0,所以CPU要定位一條代碼指令時通過CS:IP的方式定位的,如下圖所示
定位指令
當CPU執行到0x00600000處的代碼指令時,該指令為MOV AX,[0],該指令的意思是把地址0處的數據存儲到AX寄存器,這個0就是數據段的偏移地址,此時CPU會將數據段的起始地址加入到DS段寄存器中,然后將數據段寄存器的值+偏移地址即0x00601000+0=0x00601000定位到了數據123,然后將123存儲到AX寄存器中。
定位數據
上述過程就是【段基址+段偏移地址】的定位方式,之所以把起始地址加入到寄存器中,也是為了后續再執行指令或者獲取數據時,可以直接從寄存器獲取,加快CPU執行的速度。
段選擇子+段偏移地址
【段選擇子+段偏移地址】與【段基址+段偏移地址】有些相似之處,之所以采用【段選擇子+段偏移地址】主要是為了安全,原來的【段基址+段偏移地址】方式,程序員可以直接跳轉到其他代碼段和數據段,沒有任何限制,安全性全依賴于程序員的職業操守和水平,因此CPU設計者就發明了【段選擇子+段偏移地址】。
【段選擇子+段偏移地址】中的段選擇子可以認為是一個索引,這個索引指向了全局段描述符表中的一項,全局段描述表存儲在內存中,它的起始地址存儲在全局段描述符寄存器中。
全局段描述符表有很多個段描述符,每個段描述占用8個字節,這個段描述符里面就包括了段基址,另外還有一些安全性相關的描述信息例如段的可讀,可寫,可執行,段的大小等。
段選擇子存儲在了段寄存器中,總共16位,其中高13位就是全局段描述表的索引。
當CPU開始執行代碼段的第一條指令時,會將代碼段的選擇子放入到CS段寄存器中,然后CPU從段寄存器中的獲取段選擇子,然后截取選擇子的高13位獲取索引,然后根據全局描述符表寄存器的地址找到全局描述符表的起始地址,根據起始地址+索引*8找到段描述符,然后根據段描述符獲取段的基址,段的基址加上ip寄存器中的偏移地址就是指令的物理地址,如下圖所示1~6步驟所示
定位指令
當CPU執行到0x00600000處的代碼指令時,該指令為MOV AX,[0],該指令的意思是把地址0處的數據存儲到AX寄存器,這個0就是數據段的偏移地址,此時CPU會將數據段的選擇子加入到DS段寄存器中,然后CPU獲取段選擇的高13位獲取索引,然后根據全局描述符表寄存器的地址找到全局描述符表的起始地址,根據起始地址+索引*8找到段描述符,然后根據段描述符獲取段的基址,段的基址加上數據段的偏移地址就是數據的物理地址,如下圖1~6步驟所示
定位數據
上述過程就是【段選擇子+段偏移地址】的定位方式。
虛擬地址
現代的操作系統和CPU未打開分頁時采用的是【段選擇子+段偏移地址】訪問代碼和數據,而一旦打開分頁時,經過【段選擇子+段偏移地址】得到的地址不再是物理地址了,而是叫做虛擬地址,默認則是打開分頁的。
現代的操作系統和CPU采用的平坦模型,平坦模型就是整個內存就一個段,因此段基址就是0,段偏移地址就等于虛擬地址了。
下面將從以下幾個方面來闡述虛擬地址相關的話題。
1.什么是虛擬地址,物理地址,虛擬地址空間,物理地址空間,虛擬內存,物理內存?
2.什么是進程虛擬地址空間?
3.什么是虛擬頁,物理頁?
4.什么是頁表?
5.虛擬地址怎么樣訪問物理內存?
什么是虛擬地址,物理地址,虛擬地址空間,物理地址空間,虛擬內存,物理內存?
虛擬地址空間是虛擬地址的集合,假設虛擬地址空間是N位的,它的地址范圍為{02的N次方-1}即它有2的N次方個虛擬地址,例如16位的虛擬地址空間,它的地址范圍為{065535},這意味著16位的虛擬地址空間有65536個虛擬地址。
物理地址空間是物理地址的集合,假設物理地址空間有M個字節,它的地址范圍為{0M-1},M不一定是2的多少次冪,例如M=100,表示物理地址空間大小為100個字節,它的地址范圍為{099},通常情況下物理地址空間是2的冪次方,例如65536,這也是為了計算機方便處理而已,并不是強制要求的。
物理內存可以認為是一個的物理字節數組,每個物理地址指向這個物理字節數組中的一項。
虛擬內存也一樣,它也可以認為是一個物理字節數組,不過這個字節數組是存儲在磁盤上。
物理地址空間是物理內存的范圍,虛擬地址空間是虛擬內存的范圍,物理地址空間中的每個物理地址都是實打實地指向了具體的存儲單元,虛擬地址空間中每個虛擬地址指向哪里有3種情況:
a.未分配,這個虛擬地址僅僅是個數字而已,沒有任何指向。
b.未緩沖,這個虛擬地址指向了磁盤的某個字節存儲單元,里面存儲了指令或者數據。
c.已緩沖,這個虛擬地址指向了物理內存的某個字節存儲單元,里面存儲了指令或者數據。
2.什么是進程虛擬地址空間?
操作系統加載可執行文件后,創建了一個進程,這個進程就有了自己的虛擬地址空間,每個進程的虛擬地址空間都一樣,如下圖所示
進程虛擬地址空間
如上圖所示,進程的虛擬地址空間被統一劃分成了多個固定區域,例如代碼區,數據區,堆區,共享區,棧區,內核區。
代碼區和數據區域:來自于可執行文件,代碼區和數據區挨著,代碼區總是在0x0040000地址以上,0x0040000地址以下另有它用。
運行時堆區域:它初始化大小為0,隨著動態分配內存(malloc),運行時堆不斷往高地址方向擴展,有個指針brk指向了堆的最高地址。
共享庫的內存映射區域:這個區域是一些標準的系統庫,這個共享庫在物理內存中只存儲一份,每個進程將這個區域的虛擬地址映射到同一份共享庫物理內存上。
用戶棧區域:這個區域緊挨著內核區域,處于高地址處,隨著用戶棧的出棧,入棧,動態擴展,入棧向低地址方向擴展,出棧則向高地址方向收縮,棧頂指針存儲在棧寄存器(ESP)中。
內核區域:這個區域是操作系統自己代碼,數據,棧空間,內核在物理內存中只存儲一份,每個進程將這個區域的虛擬地址映射到同一份內核物理內存上。
內核和共享庫的映射
3.什么是虛擬頁,物理頁?
現代操作操作和CPU將物理內存按照固定的頁大小分成很多份,每一份叫做物理頁(PP),每一份有一個編號叫做物理頁號(PPN),這個物理頁大小通常是4KB,例如一個物理內存大小為20KB,這個物理內存可以分成5個物理頁,那么物理頁號(PPN)就是0,1,2,3,4。
虛擬內存也一樣,它的頁大小與物理內存的頁大小相同,虛擬內存也被分成了很多份,每一份叫做虛擬頁(VP),每一份的編號叫做虛擬頁號(VPN),例如假設虛擬頁大小為4KB,一個虛擬內存大小為10KB,這個虛擬內存可以分成2個虛擬頁(VP),虛擬頁號(VPN)就是0,1
每個物理頁存儲在物理內存上,每個虛擬頁存儲在磁盤上,如下圖所示
虛擬內存和物理內存
上圖的虛擬內存有8個虛擬頁,物理內存有6個物理內存頁,虛擬頁存儲在磁盤上,物理頁則存儲在DRARM上。
每個虛擬頁可以有三種狀態,未分配,已緩沖,未緩沖
未分配:虛擬頁還沒有分配磁盤空間
已緩沖:虛擬頁緩沖或者映射在了物理頁上。
未緩沖:虛擬頁分配了磁盤空間,但沒有在物理頁上緩沖。
通常操作系統加載可執行文件后,創建了一個進程,這個進程就有了虛擬地址空間,這并不意味著可執行文件已經從磁盤加載到內存中了,操作系統只是為了進程虛擬地址空間的每個區域分配了虛擬頁。
代碼和數據區域的虛擬頁被分配到了可執行文件的適當位置,此時虛擬頁狀態為未緩沖,虛擬頁指向了磁盤地址。
操作系統和共享庫的虛擬頁被映射到了物理內存,因為操作系統和共享庫已經在物理內存了,這些虛擬頁的狀態為已緩沖。
用戶棧,運行時堆的虛擬頁沒有任何分配,不占用任何空間,這些虛擬頁的狀態為未分配。
那么進程虛擬地址空間的代碼和數據,用戶棧,運行時堆的物理內存什么時候分配呢,答案就是處理器用虛擬地址執行代碼,讀取數據時,這個下一章闡述。
虛擬地址訪問物理內存
先普及幾個概念:
VPO即虛擬頁偏移量:
虛擬地址由虛擬頁號+虛擬頁偏移量組成,虛擬頁偏移量是相對某個虛擬頁的偏移量。
PPO即物理頁偏移量:
物理地址由物理頁號+物理頁偏移量組成,物理頁偏移量是相對某個物理頁的偏移量,
VPO等于PPO
頁表(Page Table)PT:
頁表是建立虛擬頁號和物理頁號映射關系的表結構,每個頁表項(PTE)包括了有效位,物理頁號,磁盤地址等信息,如下圖:
頁表與物理內存,虛擬內存的關系
由上圖可以得知,操作系統可以根據頁表項的有效位和地址信息判斷出虛擬頁目前所處的狀態即未分配,已緩沖,未緩沖
如上圖所示,頁表有8個頁表項,每個頁表項里包含一個有效位和地址信息。
當頁表項 PTE n的頁表項有效位為0時,表示虛擬頁 n沒有緩沖在物理內存,可能在磁盤或者未分配,例如PTE 0頁表項里存儲的是null,表明虛擬頁0即VP0是未分配狀態,PTE 3里存儲的是磁盤地址,表明虛擬頁 3即VP3在磁盤里,但沒有緩沖,VP3狀態為未緩沖。
當頁表項PTE n的頁表項的有效位為1時,表示虛擬頁n緩沖在物理內存,PTE n存儲了物理頁號,虛擬頁 n的狀態為已緩沖,例如PTE 1的頁表項,有效位為1,則虛擬頁VP1緩沖在了物理頁中。
頁表基址寄存器(PTBR):
每個進程都有自己的頁表,CPU執行某個進程時,會先把該進程的一級頁表起始地址存儲到頁表基址寄存器,這樣CPU查找一級頁表起始地址可以直接從寄存器查找,加快了查找效率。
好了,概念介紹到這里,先來看看虛擬地址翻譯物理地址的過程,按照一級頁表來演示,如下圖所示:
虛擬地址翻譯物理地址
上圖為虛擬地址翻譯物理地址的示意圖,可以看出VPO等于PPO。
下面看看計算機各個部件是怎么通過虛擬地址訪問物理內存的。
處理器根據虛擬地址訪問物理內存的分為頁表項命中和頁表項未命中兩種情況,頁表項命中意味著頁表項的有效位為1,頁表項存儲的是物理頁號,虛擬頁緩沖在物理頁中,未命中意味著頁表項有效位為0,此時需要發送缺頁中斷。
頁表項命中的步驟如下圖:
頁表項命中翻譯步驟
1.CPU將虛擬地址(VA)送入MMU,MMU根據頁表基址寄存器中頁表的起始地址加上虛擬頁號,找到了頁表項的物理地址PTEA。
2.MMU將PTEA送入到高速緩沖或者內存。
3.從高速緩沖或者內存中找到頁表項(PTE),返回頁表項(PTE)給MMU。
4.MMU根據PTE找出物理頁號,然后加上虛擬頁偏移量形成物理地址(PA),送入到高速緩沖或者內存。
5.高速緩沖或者內存獲取數據,返回數據給處理器。
頁表項未命中的步驟如下圖:
頁表項未命中翻譯步驟
1.CPU將虛擬地址(VA)送入MMU,MMU根據頁表基址寄存器中頁表的起始地址加上虛擬頁號,找到了頁表項的物理地址PTEA。
2.MMU將PTEA送入到高速緩沖或者內存。
3.從高速緩沖或者內存中找到頁表項(PTE),返回頁表項(PTE)給MMU。
4.MMU根據PTE,發現頁不在內存中,未命中,因此MMU發送一個缺頁中斷,交由缺頁異常處理程序處理。
5.缺頁異常處理程序根據頁置換算法,選擇出一個犧牲頁,如果這個頁面已經被修改了,則寫出到磁盤上,最后將這個犧牲頁的頁表項有效位設置為0,存入磁盤地址。
6.缺頁異常程序處理程序調入新的頁面,如果該虛擬頁尚未分配磁盤空間,則分配磁盤空間,然后磁盤空間的頁數據拷貝到空閑的物理頁上,并更新PTE的有效位為1,更新物理頁號,缺頁異常處理程序返回后,再回到發生缺頁中斷的指令處,重新按照頁表項命中的步驟執行。
虛擬地址翻譯物理地址的過程介紹完了,另外要說的是現代的CPU和操作系統為了加快虛擬地址翻譯物理地址的過程,做了以下兩點優化:
1.建立了虛擬號(VPN)和頁表項(PTE)的映射關系,存儲在TLB中,當MMU根據虛擬地址獲取頁表項時,先查詢TLB,在TLB找到了頁表項后,就不需要從高速緩沖或者內存中獲取了,找不到了才會計算頁表項地址PTEA,然后再從高速緩沖或者內存中獲取頁表項(PTE)。
2.某些熱點物理地址對應的數據,存儲在L1緩沖中,MMU根據物理地址獲取頁表項或者代碼數據時,先從L1緩沖中獲取,找不到再從內存中獲取。
上述的翻譯過程是通過一級頁表來翻譯,現在操作系統支持多級頁表,多級頁表與一級頁表比較類似,如下圖所示:
K頁表
上圖為K級頁表,頁表基址寄存器存儲的是一級頁表的地址,1到K-1的頁表的每一項存儲的下一級頁表的起始地址,K級頁表的每一項存儲的是物理頁號或者磁盤地址。
好了,關于虛擬地址,虛擬內存,虛擬地址空間的話題就介紹到這里了。
-
cpu
+關注
關注
68文章
10905瀏覽量
213031 -
數據
+關注
關注
8文章
7145瀏覽量
89585 -
操作系統
+關注
關注
37文章
6896瀏覽量
123755 -
代碼
+關注
關注
30文章
4828瀏覽量
69058
發布評論請先 登錄
相關推薦
51單片機存儲程序和數據的方式概述
IMXRT1170 Cortex M4沒有SDRAM,是否可以增加CM4的代碼和數據空間?
PLD和數據通路來釋放微控制器中CPU資源
![PLD<b class='flag-5'>和數據</b>通路來釋放微控制器中<b class='flag-5'>CPU</b>資源](https://file1.elecfans.com//web2/M00/A5/FB/wKgZomUMOyCAE8hQAAAV7HHXdns966.gif)
CPU是怎樣訪問內存的?資料下載
![<b class='flag-5'>CPU</b>是怎樣<b class='flag-5'>訪問</b>內存的?資料下載](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
Verilog代碼封裝后門訪問
![Verilog<b class='flag-5'>代碼</b>封裝后門<b class='flag-5'>訪問</b>](https://file1.elecfans.com/web2/M00/8C/CD/wKgaomSyAxyACxUEAABCYXrzBg8244.png)
MMU原理:CPU是如何訪問到內存的?
![MMU原理:<b class='flag-5'>CPU</b>是如何<b class='flag-5'>訪問</b>到內存的?](https://file1.elecfans.com/web2/M00/AD/33/wKgaomVMYLeAfRISAAAXj-dDk14708.png)
EE-132:使用VisualDSP將C代碼和數據模塊放入SHARC存儲器中
![EE-132:使用VisualDSP將C<b class='flag-5'>代碼</b><b class='flag-5'>和數據</b>模塊放入SHARC存儲器中](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論