日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

实模式与保护模式

發(fā)布時間:2025/6/15 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实模式与保护模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
本文乃fireaxe原創(chuàng),使用GPL發(fā)布,可以自由拷貝,轉載。但轉載請保持文檔的完整性,并注明原作者及原鏈接,嚴禁用于任何商業(yè)用途。
作者:fireaxe_hq@hotmail.com
博客:fireaxe.blog.chinaunix.net? ? 1.1 ??????? 保護模式的概念
1.1.1 ?什么是保護模式

在IA32下,CPU有兩種工作模式:實模式和保護模式。在實模式下,段寄存器含有段值,為訪問存儲器形成物理地址時,處理器引用相應的某個段寄存器并將其值乘以16,形成20位的段基地址。計算公式如下:物理地址 = 段值*16 + 偏移。

其中段值和偏移都是16位的,這樣通過“段:偏移”的方式達到了1MB的尋址能力。

在保護模式下,寄存器是32位的,但是為了兼容性,地址仍然用“段:偏移”的方式來表示,只不過這時的保護模式下的“段”的概念已經(jīng)發(fā)生了根本的改變,雖然段值仍然由原來的cs、ds等寄存器表示,但是此時它僅僅是一個索引,叫做選擇子,指向一個數(shù)據(jù)結構(叫做GDT,Global Descriptor Table全局描述符表或者LDT,Local Descriptor Table局部描述符表)的一個表項(叫做Descriptor描述符)。


1.1.2 ?地址轉換方式

實模式下的地址轉換方式是段地址加偏移量。段地址左移4位加偏移量得到線性地址。假設我們在ES中存入0x1000,在DI中存入0xFFFF,則線性地址ES:DI=0x1000*0x10+0xFFFF=0x1FFFF。

保護模式下的地址轉換方式也是段地址加偏移量。段地址不是直接放在段寄存器中,而是以段寄存器中的值為偏移量(選擇子)、Gdtr寄存器中的值作為基址,找到段地址。假設上面的數(shù)據(jù)不變ES=0x1000,DI=0xFFFF,現(xiàn)在ES:DI等于什么呢?公式如下:(注:0x1000=1000000000000b= 10 0000 0000 0 00)ES:DI=全局描述符表中第0x200項描述符給出的段基址+0xFFFF。實模式下稱ES為“段寄存器”,而到了保護模式就說是“選擇子”。其實它們都是一種映射,只是映射規(guī)則不同而已:在實模式下這個“地址轉換方式”是“左移4位”;在保護模式下是“查全局/局部描述表”。前者是系統(tǒng)定義的映射方式,后者是用戶自定義的轉換方式。


1.1.3 ?GDT描述符

保護模式下引入描述符來描述各種數(shù)據(jù)段,所有的描述符均為8個字節(jié)(0-7),由第5個字節(jié)說明描述符的類型,類型不同,描述符的結構也有所不同。若干個描述符集中在一起組成描述符表,而描述符表本身也是一種數(shù)據(jù)段,也使用描述符進行描述。從現(xiàn)在起,“地址轉換”由描述符表來完成,從這個意義上說,描述符表是一張地址轉換函數(shù)表。

(1) P:? 存在(Present)位。

P=1 表示描述符對地址轉換是有效的,或者說該描述符所描述的段存在,即在內(nèi)存中;

P=0 表示描述符對地址轉換無效,即該段不存在。使用該描述符進行內(nèi)存訪問時會引起異常。

(2) DPL:? 表示描述符特權級(Descriptor Privilege level),共2位。它規(guī)定了所描述段的特權級,用于特權檢查,以決定對該段能否訪問。

(3) S:?? 說明描述符的類型。

對于存儲段描述符而言,S=1,以區(qū)別與系統(tǒng)段描述符和門描述符(S=0)。

(4) TYPE: 說明存儲段描述符所描述的存儲段的具體屬性。

數(shù)據(jù)段類型

類型值?????????? 說明

?????? ----------------------------------

?????? 0??????????? 只讀

?????? 1??????????? 只讀、已訪問

?????? 2??????????? 讀/寫

?????? 3??????????? 讀/寫、已訪問

?????? 4??????????? 只讀、向下擴展

?????? 5??????????? 只讀、向下擴展、已訪問

?????? 6??????????? 讀/寫、向下擴展

?????? 7??????????? 讀/寫、向下擴展、已訪問

?

代碼段類型???

類型值?????????? 說明

----------------------------------

?????? 8??????????? 只執(zhí)行

?????? 9??????????? 只執(zhí)行、已訪問

?????? A??????????? 執(zhí)行/讀

?????? B??????????? 執(zhí)行/讀、已訪問

?????? C??????????? 只執(zhí)行、一致碼段

?????? D??????????? 只執(zhí)行、一致碼段、已訪問

?????? E??????????? 執(zhí)行/讀、一致碼段

?????? F??????????? 執(zhí)行/讀、一致碼段、已訪問

?

系統(tǒng)段類型

類型編碼?????? 說明

?????? ----------------------------------

?????? 0??????????? <未定義>

?????? 1??????????? 可用286TSS

?????? 2??????????? LDT

?????? 3??????????? 忙的286TSS

?????? 4??????????? 286調用門

?????? 5??????????? 任務門

?????? 6??????????? 286中斷門

?????? 7??????????? 286陷阱門

?????? 8??????????? 未定義

?????? 9??????????? 可用386TSS

?????? A??????????? <未定義>

?????? B??????????? 忙的386TSS

?????? C??????????? 386調用門

?????? D??????????? <未定義>

?????? E??????????? 386中斷門

?????? F??????????? 386陷阱門

?

(5) G:??? 段界限粒度(Granularity)位。

?????? G=0 表示界限粒度為字節(jié);

?????? G=1 表示界限粒度為4K 字節(jié)。

注意,界限粒度只對段界限有效,對段基地址無效,段基地址總是以字節(jié)為單位。

?

(6) D:??? D位是一個很特殊的位,在描述可執(zhí)行段、向下擴展數(shù)據(jù)段或由SS寄存器尋址的段(通常是堆棧段)的三種描述符中的意義各不相同。

?? ⑴ 在描述可執(zhí)行段的描述符中,D位決定了指令使用的地址及操作數(shù)所默認的大小。

?????? ① D=1表示默認情況下指令使用32位地址及32位或8位操作數(shù),這樣的代碼段也稱為32位代碼段;

?????? ② D=0 表示默認情況下,使用16位地址及16位或8位操作數(shù),這樣的代碼段也稱為16位代碼段,它與80286兼容。可以使用地址大小前綴和操作數(shù)大小前綴分別改變默認的地址或操作數(shù)的大小。

?? ⑵ 在向下擴展數(shù)據(jù)段的描述符中,D位決定段的上部邊界。

?????? ① D=1表示段的上部界限為4G;

?????? ② D=0表示段的上部界限為64K,這是為了與80286兼容。

? ?⑶ 在描述由SS寄存器尋址的段描述符中,D位決定隱式的堆棧訪問指令(如PUSH和POP指令)使用何種堆棧指針寄存器。

?????? ① D=1表示使用32位堆棧指針寄存器ESP;

?????? ② D=0表示使用16位堆棧指針寄存器SP,這與80286兼容。

?

(7) AVL:? 軟件可利用位。80386對該位的使用未左規(guī)定,Intel公司也保證今后開發(fā)生產(chǎn)的處理器只要與80386兼容,就不會對該位的使用做任何定義或規(guī)定。

描述符類型值說明,其中:

?????? DA_? : Descriptor Attribute

????? ?D??? : 數(shù)據(jù)段

?????? C??? : 代碼段

?????? S??? : 系統(tǒng)段

?????? R??? : 只讀

?????? RW?? : 讀寫

?????? A??? : 已訪問

?????? 其它 : 可按照字面意思理解

----------------------------------------------------------------------------

DA_32?????????? EQU?????? 4000h???? ; 32 位段

DA_DPL0???????????? EQU?????? ? 00h???? ; DPL = 0

DA_DPL1???????????? EQU?????? ? 20h???? ; DPL = 1

DA_DPL2???????????? EQU?????? ? 40h???? ; DPL = 2

DA_DPL3???????????? EQU?????? ? 60h???? ; DPL = 3

----------------------------------------------------------------------------

?存儲段描述符類型值說明

----------------------------------------------------------------------------

DA_DR????????? EQU?????? 90h? ; 存在的只讀數(shù)據(jù)段類型值

DA_DRW????????????? EQU?????? 92h? ; 存在的可讀寫數(shù)據(jù)段屬性值

DA_DRWA??????????? EQU?????? 93h? ; 存在的已訪問可讀寫數(shù)據(jù)段類型值

DA_C??????????? EQU?????? 98h? ; 存在的只執(zhí)行代碼段屬性值

DA_CR????????? EQU?????? 9Ah ; 存在的可執(zhí)行可讀代碼段屬性值

DA_CCO????????????? EQU?????? 9Ch ; 存在的只執(zhí)行一致代碼段屬性值

DA_CCOR??????????? EQU?????? 9Eh ; 存在的可執(zhí)行可讀一致代碼段屬性值

----------------------------------------------------------------------------

?系統(tǒng)段描述符類型值說明

----------------------------------------------------------------------------

DA_LDT??????? EQU?????? ? 82h???? ; 局部描述符表段類型值

DA_TaskGate? EQU?????? ? 85h???? ; 任務門類型值

DA_386TSS?? EQU?????? ? 89h???? ; 可用 386 任務狀態(tài)段類型值

DA_386CGate?????? EQU?????? ? 8Ch???? ; 386 調用門類型值

DA_386IGate EQU?????? ? 8Eh???? ; 386 中斷門類型值

DA_386TGate EQU?????? ? 8Fh???? ; 386 陷阱門類型值

----------------------------------------------------------------------------


1.1.4 ?Gdtr寄存器

保護模式下,地址轉換通過查詢GDT表實現(xiàn)。那么,系統(tǒng)如何知道GDT在內(nèi)存中的位置呢?

在80x86系列中使用寄存器Gdtr實現(xiàn),GDTR寄存器長度為6字節(jié)(48位),其中低2字節(jié)表示GDT表長度長度(limit),高4字節(jié)表示GDT表基址(實際是用于校驗Seletor是否越界)。

利用Gdtr寄存器只能找到GDT表的基址,而要找到對應的表項則需要使用Selector了。


1.1.5 ?Selector選擇子

選擇子是一個2字節(jié)的數(shù),共16位,最低2位表示RPL,第3位表示查表是利用GDT(全局描述符表)還是LDT(局部描述符表)進行,最高13位給出了所需的描述符在GDT描述符表中的地址。(注:13位正好足夠尋址8K項)

在程序運行時,段寄存器中保存的就是Selector。CPU通過Gdtr寄存器加段寄存器中保存的Selector的方式索引到對應的GDT表項,找到實際的段地址,然后加上指令中的地址,才能得到線性地址。如果沒有使用頁表結構,則這個線性地址就是物理地址了。

?RPL(Requested Privilege Level): 請求特權級,用于特權檢查。

?TI(Table Indicator): 引用描述符表指示位

?????? TI=0 指示從全局描述符表GDT中讀取描述符;

?????? TI=1 指示從局部描述符表LDT中讀取描述符。

----------------------------------------------------------------------------

選擇子類型值說明

??? SA_ : Selector Attribute

SA_RPL0????????????? EQU?????? 0???? ; ┓

SA_RPL1????????????? EQU?????? 1???? ; ┣ RPL

SA_RPL2????????????? EQU?????? 2???? ; ┃

SA_RPL3????????????? EQU?????? 3???? ; ┛

?

SA_TIG???????? EQU?????? 0???? ; ┓TI

SA_TIL????????? EQU?????? 4???? ; ┛

----------------------------------------------------------------------------

?

; usage: Descriptor Base, Limit, Attr

;??????? Base:? dd

;??????? Limit: ?dd (low 20 bits available)

;??????? Attr:? ?dw (lower 4 bits of higher byte are always 0)

%macro Descriptor 3

?????? dw?? %2 & 0FFFFh??????????????????????????? ; 段界限 1???????????????????????? (2 字節(jié))

?????? dw?? %1 & 0FFFFh??????????????????????????? ; 段基址 1???????????????????????? (2 字節(jié))

?????? db??? (%1 >> 16) & 0FFh???????????? ; 段基址 2???????????????????????? (1 字節(jié))

?????? dw?? ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)????? ; 屬性 1 + 段界限 2 + 屬性 2???????? (2 字節(jié))

?????? db??? (%1 >> 24) & 0FFh???????????? ; 段基址 3???????????????????????? (1 字節(jié))

%endmacro ; 共 8 字節(jié)


1.1.6 ?CR0寄存器

CR0是x86系列cpu的保護控制寄存器。CR0的第0位PE位用于設置CPU工作模式。

PE=0:實模式

PE=1:保護模式





1.1??進入保護模式的主要步驟:
1.1.1 ?GDT表

GDT表是存儲GDT描述符的數(shù)組,每一個描述符對應著一個段。GDT表中的第一項必須為全0。表項類型為結構體Descriptor,結構如下:

; usage: Descriptor Base, Limit, Attr

;? ??%1??? Base:? dd

;??? %2??? Limit: dd (low 20 bits available)

;??? %3??? Attr:? dw (lower 4 bits of higher byte are always 0)

%macro Descriptor 3

???dw??%2 & 0FFFFh????????; 段界限 1??? (2 字節(jié))

???dw??%1 & 0FFFFh??????? ; 段基址 1??? (2 字節(jié))

???db??(%1 >> 16) & 0FFh??; 段基址 2??? (1 字節(jié))

???dw??((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)?; 屬性 1 + 段界限 2 + 屬性 2? (2 字節(jié))

???db??(%1 >> 24) & 0FFh??; 段基址 3????(1 字節(jié))

%endmacro ; 共 8 字節(jié)

根據(jù)nasm編譯器的規(guī)則,結構體定義以%macro開始,以%endmacro結束。結構體名為Descriptor,宏名后的3表示該結構體有三個成員變量。

GDT表的定義方式如下:

[SECTION .gdt]

; GDT?????????????????????? ????Base Addr?? Limit?????? ???Attrib

LABEL_DES_GDT:??? Descriptor ??0,???? ?????0,????????? ???0

LABEL_DES_CODE32: Descriptor?? 0, ?????????Code32Len - 1,? DA_C + DA_32

LABEL_DES_VIDEO:? Descriptor? ?0B8000h, ???0ffffh,?? ??????DA_DRW

; GDT end

這里可以看到給結構體賦值的方式,每一項對應結構體中的一個成員變量。以表項LABEL_DES_VIDEO為例,0B8000h對應%1,0ffffh對應%2,DA_DRW對應%3。

注意:表項LABEL_DES_CODE32保存的是我們要跳入的32位代碼段的GDT表項,其中Base Addr是0,因為此時還不知道32為代碼段的地址,在后面的16為代碼段中才會設置它。


1.1.2 ?Gdtr

GdtLen ?equ $ - LABEL_DES_GDT?? ; Gdt Len

GdtPtr? ?dw ?GdtLen - 1????? ; Gdt Limit

??????? ?dd? 0?????????????? ; Gdt Base Addr

GDT表的地址保存在寄存器Gdtr中,該地址首先通過上面的語句計算而得后存在變量GdtPtr中,之后才加載。GdtPtr低2字節(jié)保存GDT表長度,通過“$ - LABEL_DES_GDT”計算而得。GdtPtr高4字節(jié)保存GDT表基址,這里先置0,后面會存入地址。

?


1.1.3 ?Selector選擇子

; Gdt Selector

SelectorCode32? equ LABEL_DES_CODE32 - LABEL_DES_GDT

SelectorVideo?? equ LABEL_DES_VIDEO - LABEL_DES_GDT

?

選擇子Selector中保存的是各段對應GDT表項相對地址,通過上面的語句計算而得。

?


1.1.4 ?16位段與32位段

[SECTION .s16]

[BITS 16]

……

[SECTION .s32]

[BITS 32]

……

由于本程序實現(xiàn)了有實模式到保護模式的跳轉,所以需要在程序中定義兩個代碼段,一個是16位段;一個是32位段。


1.1.5 ?初始化32位代碼段描述符

?????? ; Init 32 bits code segment descriptor

??? xor eax, eax

??? mov ax, cs

??? shl eax, 4

??? add eax, LABEL_CODE32

??? mov word [LABEL_DES_CODE32 + 2], ax

??? shr eax, 16

??? mov byte [LABEL_DES_CODE32 + 4], al

??? mov byte [LABEL_DES_CODE32 + 7], ah

?

首先要設置32為代碼段對應GDT表項的基址。基址對應著表項中的第2、3、4、7,四個字節(jié)。


1.1.6 ?準備加載gdtr

??? ; Prepare for loading gdtr

??? xor eax, eax

??? mov ax, cs

??? shl eax, 4

??? add eax, LABEL_DES_GDT

??? mov dword [GdtPtr + 2], eax

這段代碼用于設置變量GdtPtr,長度為2字節(jié)。


1.1.7 ?加載gdtr

??? ; Load gdtr

??? lgdt [GdtPtr]

此處加載gdtr寄存器,x86使用專門的指令lgdt實現(xiàn)gdtr寄存器的設置。


1.1.8 ?關閉中斷

??? ; close int

??? Cli

由于實模式與保護模式下的中斷模式不同,所以在實模式/保護模式轉換時必須關閉中斷。


1.1.9 ?打開A20

??? ; open A20

??? in al, 92h

??? or al, 00000010b

??? out 92h, al

80286及之前的cpu最大尋址空間為1M,超過1M的地址(也就是使用了A20之后的地址線),會開始從0重新計算,即使跳入保護空間,也無法使用超過1M的地址。

80386開始,增加了保護模式,尋址空間變?yōu)?G。為了與80286之前的cpu兼容,超過1M的地址平時是關閉的,只有打開A20后才能訪問超過1M的地址。

上面只是打開A20的一種方式,但不是唯一的方式。


1.1.10 ????????? 設置cr0的PE位

??? ; open protected mode

??? mov eax, cr0

??? or? eax, 1

??? mov cr0, eax

此處打開cr0的PE位,實際上就使能了保護模式,也就是說,“mov cr0, eax”這一句后,系統(tǒng)就運行于保護模式下了。但是,此時ics的值仍然是實模式下的值,我們需要把代碼段的Selector選擇子裝入cs。


1.1.11 ????????? 跳入保護模式

??? ; jump into protected mode

??? jmp dword SelectorCode32:0???

?

這個跳轉是為了設置cs寄存器,其目的是選擇子SelectorCode32對應的GDT描述符LABEL_DESC_CODE32對應的段首地址,即標號LABEL_??? CODE32C處。

該句指令還在16位段中執(zhí)行,而目標地址卻是32位的,從這一點上看,他是混合16位于32位的代碼。所以,jmp后的dword就必不可少了。如果沒有dword,編譯出來的只是16位代碼。假設目標地址偏移量為0x12345678,執(zhí)行jmp SelectorCode32:0x12345678,則等價于jmp SelectorCode32:0x5678。

Nasm編譯器的好處之一就是可以通過jmp后添加dword,指定編譯后為32位指令。

至此,我們真正跳入了保護模式。

?


1.1.12 ????????? 顯示字符

LABEL_CODE32:

??? mov eax, SelectorVideo

??? mov gs, eax

??? mov edi, (80 * 6 + 6) * 2????? ; Line: 6, Column: 6

??? mov ah, 0Ch???????????????? ??????? ; 0000: background(black)??? 1100: foreground(red)

??? mov al, 'P'

??? mov [gs:edi], ax

這是進入保護模式后執(zhí)行的代碼。SelectorVideo選擇子對應著顯存的基址,我們通過把‘P’放入顯存,實現(xiàn)了字符‘P’的顯示。





? 今天終于實現(xiàn)了由匯編進入c程序,由于C程序都是在32位模式下操作的,所以需要由匯編中進入保護模式,然后才能進入C程序。保護模式下與實模式有一點不同,要注意個段的屬性。
???? 實模式下段地址設置:
?mov ax,?cs
?mov ds, ax
?mov ss, ax
?mov es, ax
?mov sp, 01000h
????? 保護模式下段地址設置:
?mov eax, SelectorStack
?mov ds, eax
?mov ss, eax
?mov es, eax
?mov sp, 01000h
???????實模式中可以用代碼段寄存器cs來設置堆棧、數(shù)據(jù)等段寄存器;保護模式中斷寄存器是設置了代碼段屬性的(DA_C + DA_32),所以只能用用于代碼段,堆棧、數(shù)據(jù)段等需要進行數(shù)據(jù)操作的段,必須設置其他GDT段(屬性為DA_DRW)。









?

總結

以上是生活随笔為你收集整理的实模式与保护模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。