我們定義乙個區域性變數,然後列印出這個區域性變數的位址,那麼這個區域性變數的位址是線性位址?實體地址?還是邏輯位址?要明白這些,先來看看以下的知識吧。
x86體系:指的是特定微cpu執行的有些
計算機語言
指令集,定義了
晶元的基本用規則
cpu的位數:alu一次性最多能處理的整數的位元組數,也即alu的寬度,alu的資料是從暫存器拿來的,暫存器中的值是從資料匯流排拿來的,所以也可以說是資料匯流排的條數。但不可以說是位址匯流排的條數,因為我們經常說32位位址匯流排是因為32位的作業系統資料匯流排和位址匯流排都是32條。但是16位的資料匯流排是16條,位址匯流排是20條,8位的資料匯流排是8條,位址匯流排是16條。
x86體系之前8位的cpu實際上它的位址匯流排是16條的,也即它的最大定址位址可以達到64k。8086是20位位址匯流排,可以達到1m
8080/8085晶元,暫存器也就1個位元組,但是位址匯流排是16位的,也即位址的格式都是兩個位元組的(eg:0x0012),這個位址就沒辦法放入暫存器中了(資料的位數和位址的位數不對等),只能分開存放了。所以究其歷史原因,當時用的是16位的彙編指令解決(這個很複雜,不做介紹,實際上是我也不會啊!!!)
接下來我們就要進入x86體系了,既然是體系那就要保證你之後所創立的新的晶元要相容這個體系之前的晶元。所以建立的第乙個8086是至關重要的,這時候8086已經達到16位了,but我們要找尋更大的位址,所以我們的位址匯流排擴大為20條。那麼我們這時如果要解決資料的位數和位址的位數不對等,難道要向x86之前那樣,整合20位的彙編指令嗎?答案顯然是不,因為那個彙編設計起來非常複雜,而且我們要開創乙個新的體系。所以8086晶元開始我們就在cpu裡面增加了4個暫存器(當然了這4個暫存器也是2位元組噠)
cs (
**段暫存器) ds(資料段暫存器) ss/es(堆疊段暫存器) ip(偏移量暫存器)
在這個體系中有這麼乙個規定,他把記憶體(物理記憶體)劃分成為乙個段乙個段的,規定每個記憶體段的起始位址必須是16的倍數,又因為ip暫存器最大可以偏移2^16(64k),所以記憶體中的段的大小就是在16到64k之間,那就是你的**跟資料堆疊有多少。
所以這個20位的位址怎麼放到16位的暫存器中呢?因為我們上面規定了每個段的起始位址都是16的倍數,所以我們可以知道,乙個數能被16整除,2進製的這個數滿足怎樣的特徵呢?
例如0x00010000(16) 0x00100000
(32)
0x0100
0000
(64)
可以看出能被16整除的數,它的低4位都是0。所以我們就可以將記憶體段的起始位址的高16位儲存在相應的段暫存器中。
所以在這種情況下,我們就需要這樣定址:
我們cpu可以根據指令的解碼(eg:mov lea call)可以判斷出我們對於那個段進行的操作。比如我們是mov,那麼這就是對於資料段的操作,那麼我們如何找到我們所要操作的資料位址在哪呢?首先我們就會去訪問ds,因為這個ds存的是資料段高16位的位址,所以我們就需要將ds中的資料左移4位,才是真正的段的起始位址,那麼資料在這個段的那個位置呢?這就要看我們的ip的暫存器了,ip暫存器放的就是偏移量,所以我們就可以找到資料的位址。
因為沒有作業系統,也就沒有許可權的控制,只要呼叫驅動介面,就可以更改段暫存器中的數值,那麼就可以直接更改到物理記憶體上的東西,沒有作業系統的保護。我們將這種沒有作業系統的保護的機制叫做實位址模式(實模式),
實模式是非常不安全的。
實模式下能訪問的最大物理記憶體也就是2^20(1m),對於x86體系之後的晶元(例如80386),在作業系統沒有啟動起來,通上電的時候實際上強制進入的是實模式(也即8086的模式)。所以我們看到linux核心的**,核心的image(映象)載入的時候都載入到了0x100000(1m),為什麼從這個位址開始載入?因為在這個之前都是實模式執行的,實模式所佔的記憶體之後才是核心的映象所放置的位置。那麼這個前1m放的什麼東西?比如軟體的驅動**,顯示卡的快取等等。
虛擬位址是從0xc0100000載入。
我們在訪問記憶體的時候需要什麼資訊呢? 1:
記憶體的起始位址 2:
記憶體段的大小(如果沒有這個大小size,我們如果給ip位址乙個非常大的值,我們就有可能從**段偏移到資料段了,所以如果size 3:
記憶體的訪問許可權(比如:**段唯讀,資料段讀寫…)
還有諸如此類的資訊
那麼這些東西不可能全放在段暫存器中,我們的段暫存器是16位的(即便是80386仍然是16位,因為這是8086有的,以前存在的東西在這個體系中是不能被更改的,只能新增,這樣才可以向前相容)
所以對於這些資訊,我們必須要重新的一種結構,所以從80386以後,我們新增了幾個暫存器
gdtr
全域性的段描述附表暫存器 ldtr 區域性的段描述表暫存器
gdtr
存放的是gdt(全域性的段描述附表,在記憶體中(物理記憶體),可以將它視為陣列)
要訪問這個陣列中的元素,還需要乙個下標,那我們下標放在那裡呢?圖中可以看出記憶體的起始位址在陣列中,那麼我們的段暫存器就空下來了,我們就可以將這些下標放在段暫存器中了。
所以從80386開始,我們這些段暫存器就不存放記憶體的起始位址,而是存放的是段描述附表的索引。
那麼在這種情況下,我們就無需用實模式底下的那樣去定址了,而是首先根據指令的解碼(eg:mov lea call)判斷出我們對於那個段進行的操作。比如我們是mov,那麼我們就會去訪問ds,根據這個ds就可以找到gdt中的索引資訊,訪問到記憶體。
這個段暫存器中的索引是如何存放的呢?
段描述符表項是什麼結構呢?我們來看一下
我們現在核心已經不用ldt了,用的是gdt,gdt是所有程序共享的,ldt是每個程序獨有的。我們以gdt來舉例
保護模式下記憶體分段的位址對映是什麼?
檢查有沒有開啟分頁機制,我們cpu中有這幾個暫存器
cr0
最高pg位 0未開啟分頁 1開啟分頁
cr2
發生缺頁異常的虛擬位址
cr3
也目錄的起始位址
cr4 pae
位 實體地址擴充套件 0表示未開啟 1表示開啟
關於分段分頁對映,明日再更。
HPS 虛擬位址對映
hps 如何對fpga外設進行操作?hardware 在qsys中將外設連線到axi bridge上 software 對映外設實體地址到到應用程式可以操作的虛擬位址,應用程式通過得到的虛擬位址入口控制外設。也就是說hps訪問fpga中的外設時,可以使用mpu來進行虛擬位址的分配 mpu將以有的外設...
32位Linux系統虛擬位址對映
ia32體系即intel32位體系架構,也被稱為i386 x86 32或x86。在intel公司1985年推出的80386微處理器中首先使用。用以取代之前的x86 16位架構,包括8086 80186 80286晶元。談到這兒,就不得不說說x86架構的發展歷史。intel 8086是由intel於1...
Linux虛擬位址空間
在多工作業系統中,每個程序都執行在屬於自己的記憶體沙盤中。這個沙盤就是虛擬位址空間 virtual address space 在32位模式下它是乙個4gb的記憶體位址塊,這篇部落格均是x86架構的 1.位址空間分布 2.核心位址空間 從pkmap base 到 fixaddr start用於對映高...