接下來將進入x86保護模式程式設計的一些細節。
從80386處理器開始,cpu有了四種執行模式
實模式保護模式
虛擬8086模式
smm模式工作模式是指cpu的定址方式、暫存器大小等。
cpu的實模式
在8086時代,cpu以實模式執行
cpu剛剛上電後,也以實模式啟動
參考資料:
(最開始的時候,cpu一共只有20位位址線、8個16位的段暫存器)
實模式下,記憶體定址方式由16位暫存器的內容乘以10h當作段基位址(由段暫存器提供),加上16位偏移位址形成20位實體地址(段基址:段偏移量)。最大定址空間1mb,最大分段64kb,可以使用32位指令。
段暫存器一共有6種:
cs、ds、ss、es、fs、gs
段暫存器
段暫存器是因為對記憶體的分段管理而設定的。計算機需要對記憶體分段,以分配給不同的程式使用。
在進行記憶體分段時,需要以下資訊:
段的大小
段的起始位址
段的屬性
需要使用8個位元組即64位儲存這些資訊
段暫存器只有16位,因此,段暫存器只能儲存segment selector,由其對映到存在記憶體中的全域性段號記錄表(gdt)來讀取段的資訊。
cs是**段。指向存放程式的記憶體。ip是存放下條待執行指令的偏移量,合在一起就是下條指令位置。
偏移量由通用暫存器提供,也是16位。
實體地址=段位址<<4+段內偏移
ds是資料段。預設。
ss是堆疊段。指向堆疊的記憶體段基位址,sp指向該堆疊的棧頂,合在一起可以訪問棧頂單元。加上bp可以訪問整個堆疊。
es是附加段。串操作指令中目的串所在的段。
將記憶體分段後,每個段都有乙個段基址,段暫存器儲存這個段基址的高16位,16位段基址左移4位後可以構成20位的段基址。
fs和gs沒有定義,由作業系統賦予它們目的。
實模式之所以稱之為實模式,是因為它的實體地址是真實的。
任意程式可以修改任意位址的變數
保護模式
隨著cpu的發展,實模式下的記憶體位址計算方式不再適用。
保護模式能提供更大的空間、更靈活、更安全的記憶體訪問。
記憶體定址方式需要相容老辦法,即(段基址、段偏移量)。
這個時候cpu內的通用暫存器全部換為32位,但是段暫存器還是16位的。
偏移值和實模式下一樣,仍然由通用暫存器提供,只是大小變成了32位。
將關於記憶體段的限制資訊放在gdt即全域性描述符表中,裡面的每乙個項稱之為段描述符。
段暫存器在保護模式下存放的東西類似於陣列索引。
使用專用暫存器gdtr指向全域性描述符表。
gdtr的結構:0-15存放gdt的長度,16-47存放基址。
乙個段描述符只能用來定義乙個記憶體段。
段界限:段邊界擴張法最值,即最大擴充套件多少、最小擴充套件多少。它的單位由g決定,g=1時單位為4kb,g=0時單位為位元組。
實際段界限邊界值 = (段界限+1) * 單位大小 - 1
若偏移位址超過段界限,則會報錯
此時的段暫存器內儲存的是乙個「選擇子」
選擇子的0-2位是rpl,描述特權級別
3位是ti,ti=0表示在gdt中索引,ti=1表示在ldt中索引
3-15位是描述符索引值
保護模式下,程式不能隨心所欲地修改任意位址的變數
虛擬8086模式
用於在保護模式下執行16位**
smm模式
不對程式設計師開放,不關心
cpu內部有5個32位的控制暫存器:cr0-cr3,cr8
cr0:含有控制cpu操作模式和狀態的標識
cr1:保留不用
cr2:儲存導致頁錯誤的線性位址
cr3:含有頁目錄表的物理記憶體基址
cr0中的保護控制位:pe
pe設定->開啟了保護模式
pg設定->開啟分頁機制(pe、pg都要設定)
cpu一進入保護模式立刻按照保護模式定址,這要求我們要在cpu進入保護模式前放好gdt
我們的核心剛剛啟動時,機器的狀態是這樣的:
在實模式下,cpu只有1mb的定址空間,所以相當於gdt被限制在這裡了eax 0x2badb002 732803074
ecx 0x1c300 115456
edx 0x2be00 179712
ebx 0x2bd20 179488
esp 0x7ffc 0x7ffc
ebp 0x0 0x0
esi 0x2be78 179832
edi 0x80 128
eip 0x10051f 0x10051f eflags 0x6 [ pf ]
cs 0x8 8
ss 0x10 16
ds 0x10 16
es 0x10 16
fs 0x10 16
gs 0x10 16
grub在載入核心後,cs指向基位址為0x0、長度為4g-1的**描述符,ds指向了基位址為0x0、長度為1的資料段描述符
也就是,grub載入後,已經進入了平坦模式。
分段是intel的cpu一致保持的一種機制,分頁只是保護模式下的一種機制
如何繞過分段直接使用分頁?
使用平坦模式,即將整個記憶體作為乙個分段。
當整個虛擬空間為乙個起始位址為0、限長為4g的段時,給出的偏移位址就在數值上等於段機制處理後的位址了。
因此,此時計算機可以相容實模式
在grub引導後,我們的計算機已經進入了保護模式了
但是我們仍然需要再來一次,乙個是學習,另乙個是後期還要用到@ring: 0
cs = 0x8
ss = 0x10
ds = 0x10
es = 0x10
首先需要構建資料型別
根據我們上面的介紹,構建如下的資料結構
注意第二個結構體的// 定義gdt結構
typedef
struct
gdt_t;
typedef
struct
__attribute__
((packed)
)gdtr_t;
__attribute__屬性
!特別重要
沒有加上這個屬性,結構體大小為64,加上這個屬性,結構體大小為48,差了特別多!
其次,讓我們構建初始化gdt的函式
這裡的#define gdt_len 5
static gdt_t gdt[gdt_len]
;static gdtr_t gdtr;
static
void
gdt_set
(int num, uint32_t base,
uint32_t limit, uint8_t access, uint8_t gran)
;void
init_gdt()
static
void
gdt_set
(int num, uint32_t base,
uint32_t limit, uint8_t access, uint8_t gran)
gdt_flush
負責更新gdrt
這個操作只能使用彙編完成
注意這個jmp語句:[global gdt_flush]
gdt_flush:
mov eax, [esp + 4]
lgdt [eax]
mov ax, 0x10
mov ss, ax
mov ds, ax
mov gs, ax
mov es, ax
mov fs, ax
jmp 0x08:.flush
.flush:
ret
此處的jmp有兩個作用
重新整理cs暫存器
重新整理快取記憶體與流水線
這是nasm裡面的遠跳轉的寫法
寒假學習第四天
今天進行了spark的安裝。右擊,複製鏈結如下 在master的命令列中輸入 wget 複製結果如下 輸入命令 wget 2.2 解壓 輸入命令 tar zxf spark 2.4.0 bin hadoop2.7.tgz 2.3 遷移目錄 輸入命令 sudo mv spark 2.4.0 bin h...
第四天學習
一 權重關係 樣式表的權重關係 內聯樣式表的權重最大!內部和外部樣式的權重,和書寫的前後順序有關!放在後面的會把放在前面的樣式覆蓋掉 網頁的布局 先做上下排版 再做左右排版 從外往裡 二 css語法 選擇符選擇符 選擇符就是給標籤起名字 型別選擇符 標籤選擇符 所有的html標籤可以直接當做選擇符進...
C Primer學習第四天
第四章 陣列和指標 c 語言提供了兩種類似於vector和迭代器型別的低階復合型別 陣列和指標。與vector型別相似,陣列也可以儲存某種型別的一組物件 而它們的區別在於,陣列的長度是固定的。陣列一經建立,就不允許新增新的元素。指標則可以像迭代器一樣用於遍歷和檢查陣列中的元素。現代c 程式應盡量使用...