操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    T之家9月21日消息 在 Windows 10 PC 中,你偏愛使用桌面版的 OneNote (原 OneNote 2016 ),還是 OneNote for Windows 10(僅在 Windows 10 上提供的 Microsoft Store 應用)?

    微軟幫助和支持今天表示,在 2020 年 10 月之后,微軟將繼續對桌面版 OneNote 提供主流支持。這表示繼續使用 OneNote 的同時也將會收到 “功能更新”。這意味著你可以繼續使用它,并將會看到新的功能更新。

    微軟 OneNote 支持日期將與 Office 2019 支持日期保持一致(主流支持日期為 2023 年 10 月 10 日,擴展支持日期為 2025 年 10 月 14 日)。

    IT之家了解到,對于包括客戶端應用和 Office 2019 的 Microsoft 365 訂閱,OneNote 桌面應用(以前稱為 OneNote 2016)現在默認隨 Word、PowerPoint 和 Excel 一起安裝

    OneNote for Windows 10 已預安裝在 Windows 10 設備上,也可以從 Microsoft Store 免費下載。

    如果你使用的是 Windows 10,則 OneNote 的兩個 Windows 版本均可安裝在同一臺電腦或設備上,并且可同時使用。

    在操作系統中,全局描述符是什么?GDT又是什么?在進入保護模式之前,準備好GDT和GDT中的描述符是必須的嗎?用匯編代碼怎么創建描述符?本文解答上面幾個問題。

    在實模式下,CPU是16位的,意思是,寄存器是16位的,數組總線(data bus)是16位的,但地址總線是20位的。物理內存地址的計算公式是:
    $$
    物理地址 = 段地址 * 16 + 偏移量
    $$
    段地址和偏移量都是16位的,能尋址的最大內存地址是1M。

    1M是怎么計算出來的?2的20次方就是1M,能表示的內存地址是 0~(2的20次方-1)。用簡單例子來理解,1位十進制數能表示的最大數是10 - 1 = 9,但1位十進制數能表示的數卻是 0 ,和 1-9 ,總計10個數字。

    若一個內存地址是20:30,最終內存地址是:20 * 16 + 30

    在保護模式下,內存地址仍然用“段地址:偏移量”的方式來表示。不過,“段地址”的含義不同于實模式下的“段地址”。在實模式下,段地址是物理地址的高地址部分,具體說,是高16位部分。而在保護模式下,段地址是選擇子,指向一個結構,這個結構描述了一個內存區域,告知該區域的內存地址從哪里開始,在哪里結束,還告知了這片內存能不能被訪問、能不能被讀取等數據。這個結構組成一個集合,叫GDT,而這個結構叫GDT項,它有一個術語,叫“描述符”。

    GDT的作用是提供段式存儲機制。段式存儲機制由段寄存器和GDT共同提供。段寄存器提供段值,即描述符在GDT中的索引,也就是選擇子。根據選擇子在GDT中找到目標描述符。這個描述符中包含一段內存的初始地址、這段內存的最大地址、這段內存的屬性。

    GDT的構成

    GDT項即全局描述符的長度是8個字節,64個bit,64個位,063位,而不是164位。下圖是寫了位編號的8個字節。真實的全局描述符是不折行的,這里無法在一行顯示全部數據,因此折行了。

    63|62|61|60|59|58|57|56| 55|54|53|52|51|50|49|48| 47|46|45|44|43|42|41|40| 39|38|37|36|35|34|33|32| 31|30|29|28|27|26|25|24| 23|22|21|20|19|18|17|16| 15|14|13|12|11|10|09|08| 07|06|05|04|03|02|01|00|
    

    15|14|13|12|11|10|09|08| 07|06|05|04|03|02|01|00|。段界限1。段界限的 0~15 位。描述符的 0~15 位。

    39|38|37|36|35|34|33|32| 31|30|29|28|27|26|25|24| 23|22|21|20|19|18|17|16|。段基址1。段基址的 0~23位。描述符的 16~39位。

    55|54|53|52|51|50|49|48| 47|46|45|44|43|42|41|40|。很復雜,很碎片化,需進一步放大觀察。

    43|42|41|40|,TYPE。4位。

    44,S。是否為系統段(待驗證)。1位。

    46|45,DPL。2位。

    47,P。1位。

    上面是一個字節,下面是第二個字節。

    51|50|49|48|。段界限2。段界限的第 16~19 位。描述符的第 48~51 位。段界限一共有20位。

    52。AVL。1位。

    53。0。1位。

    54。D/B。1位。

    55。G。1位。

    段屬性占用空間的位數:4 + 1 + 2 + 1 + 1 + 1 * 3 = 12。

    63|62|61|60|59|58|57|56|。段基址2。段基址的第 24~31 位。描述符的第 56~63 位。段基址一共有32位。

    描述符的結構比較復雜,要記住它,有點困難,不過并非不可能記住。作者覺得沒有必要一個字節不差地背誦出來。

    選擇子

    描述符的選擇子的長度是16位。

    15|14|13|12|11|10|09|08| 07|06|05|04|03|02|01|00|
    

    01|00|,RPL。

    02,T1。

    15|14|13|12|11|10|09|08| 07|06|05|04|03,描述符在GDT中的索引。

    段式存儲機制的尋址方式

    段地址存儲的是描述符的選擇子,根據選擇子能找到GDT中對應的描述符。從描述符中獲取段基址,然后加上段式存儲機制中的偏移量,就是線性地址。在當前語境下,線性地址等同物理地址。

    概念比較

    邏輯地址。段式機制的地址,例如“段地址:偏移量”,就是邏輯地址。

    線性地址。在保護模式下,用邏輯地址中的段地址從GDT中找到描述符,然后從描述符中獲取段的基址,段基址加上偏移量的結果就是線性地址。

    如上文所言,線性地址目前可視為物理地址。開啟分頁機制后,線性地址不能等同于物理地址。物理地址是物理內存的一個編號。

    作者的疑問

    進入保護模式前,為什么需要創建好描述符、選擇子、GDT?這些是必要條件嗎?

    作者曾認為這些不是必須。再次了解段式存儲機制后,改變了看法:進入保護模式前,必須準備好GDT、描述符和描述符選擇子。這是由保護模式下的內存尋址方式決定的。

    無論是在實模式下還是保護模式下,都需要使用內存。在保護模式下,怎么找到某片內存呢?保護模式下,使用段式機制。回憶一下,段式存儲機制的尋址方式是:
    $$
    段地址(選擇子)-----》在GDT中找到描述符----》在描述符中找到段基址----》段基址+偏移量 = 線性地址
    $$
    不在進入保護模式前準備好選擇子、GDT、描述符,就無法在保護模式中使用內存。

    作者還有一個疑問:上面的尋址過程是CPU自動完成的嗎?

    實現描述符

    C語言

    描述符

    下面內容的前提是,32位CPU。

    struct {
    	int segmentLimit1:16;															// 段界限1
      int segmentBaseAddress1:24;											// 段基址1
      char attributeType:4;														// 段屬性,TYPE
      char attributeS:1;															// 段屬性,S
      char attributeDPL:2;														// 段屬性,DPL
      char attributeP:1;															// 段屬性,P
      char segmentLimit2:4;														// 段界限2
      char attributeAVL:1;														// 段屬性,AVL
      char attributeZero:1;														// 段屬性,值為0
      char attributeDB:1;															// 段屬性,DB
      char attributeG:1;															// 段屬性,G
      char segmentBaseAddress2;												// 段基址2
    }GlobalDescriptor;
    

    上面的用法是錯誤的。對位域的使用是錯的,換成int來使用位域也無能力寫正確,因為太麻煩。在這個知識點耗費了不少時間。

    參考書中代碼后,寫出下面的代碼:

    struct{
      unsigned short segmentLimitLow;															// 段界限1,16位,0~15 位。描述符的第 0~15 位。
      unsigned short segmentBaseAddressLow;												// 段基址低16位,0~15 位。描述符的第 16~31 位。
      unsigned char	segmentBaseAddressMid;												// 段基址 16~23 位。描述符的第 32~39 位。
      unsigned char attribute;																		// 段屬性。描述符的第 40~47 位。
      unsigned char segmentLimitHight_attribute2;				// 段界限 16~19 位,第 20~23 位是段屬性。描述符的第 48~55 位。
      unsigned char	segmentBaseAddressHigh;												// 段基址 24~31 位。描述符的第 46~63 位。			
    }GlobalDescriptor;
    

    段基址雖然存儲在描述符的第 16~39 位 和第 24~31 位兩段連續的空間中,但用C語言表示它的時候,卻人為地將它拆分成了“低位”、“中位”和“高位”三部分,也就是,把描述符的第 16~39 位拆分成了第 16~31 位和第 32~39 位兩段。在C語言中,沒有現成的能存儲23位的整數類型,卻用能存儲16位和8位的整數類型。將段基址連在一起的24位拆分,用C語言表示更方便。

    C語言中的位域

    前面已經用到了位域,那就簡單學習一下位域的知識吧。

    用兩段代碼開始。

    struct{
    	unsigned int age;
    	unsigned int height;
    }Person;
    
    struct{
    	unsigned int age:3;
      unsigned int height:4;
    }Person2;
    

    第二段代碼使用了位域,第一段代碼是普通的struct結構。位域語法與struct的差異僅在于聲明成員變量的語法不同。

    struct結構中,聲明成員變量的語法是unsigned int age。在位域中,聲明成員變量的語法是unsigned int age:3。后者指定了成員變量使用的bit的數量,是3個,而不是1個字節、8個bit。

    第一段代碼創建的Person占用8個字節,第二段代碼創建的Person2占用4個字節。

    抽象出位域的成員變量的聲明語法:dataType VariableName:bitCountdataType只能是int系列的整數類型,即只能是intunsigned intsigned int 三種類型,不能是char等類型。這是語法規定。bitCount不能超過8個字節。

    nasm匯編

    用匯編語言表示描述符,是作者寫本文的終極目的,前面的一切都是鋪墊和基礎。C語言表示描述符,在前面寫出來,是因為它是作者理解描述符的匯編代碼的大功臣。作者在看描述符的匯編代碼前,沒有學過匯編語言,所以第一次看描述符的匯編代碼時,怎么都理解不了。看了別人寫的描述符的C語言代碼后,才恍然大悟,突然理解了描述符的的匯編代碼。

    所以,在前文給出描述符的C代碼,一是為了紀念這個大功臣,二是讓與曾經看不懂匯編代碼的作者一樣的讀者也能借住C代碼理解匯編代碼。當然,可能是作者多慮了,讀者朋友才不會像作者這么愚鈍呢。

    不使用宏

    第一個問題,創建一個描述符,例如DESC_VIDEO,語法是什么樣的。

    第二個問題。描述符的實質是段基址、段界限和段屬性。是直接用代碼堆砌出描述符呢還是根據給定的段基址、段界限和段屬性經過運算拼湊出描述符?

    先解答第二個問題。直接用代碼堆砌出描述符的匯編代碼如下:

    DESC_VIDEO	dw	3120h																											; 描述符的第 0~15 位
    	dw	111Fh																																; 描述符的第 16~31 位
      db	EFh																																	; 描述符的第 32~39 位
      db	42h																																	; 描述符的第 40~47 位
      db	00h																																	; 描述符的第 48~55 位
      db	FFh																																	; 描述符的第 56~63 位
    

    與前面的C代碼比較,每行對應一個struct的成員變量。從上面的匯編代碼能看出段基址、段界限和段屬性是什么嗎?看不出來,需要計算。而且,總不能拿到給定的段基址、段界限和段屬性后,先將它們轉換成二進制,然后再分割填到上面的代碼中吧?最好是給定段基址、段界限和段屬性后,經過一段代碼處理,就自動構建了描述符。這就是下面要寫的方式。

    匯編中的宏類似C語言中的函數,給定參數,函數會完成一些功能。這個宏接收段基址、段界限和段屬性,然后生成描述符。

    宏的語法是什么樣的?創建一個宏的模板是:

    %macro macroName paramCount
    	;some code
    	;some code
    %endmacro
    

    創建描述符的宏是:

    ; 三個參數依次是:base(段基址)、limit(段界限)、attribute(段屬性)
    ; 在宏中需用到這三個參數時,對應的代號分別是:%1、%2、%3。
    ; base--32位,limit--20位,attribute--12位
    %macro Descriptor	3
    	dw	%2 & FFFFh															; 段界限的第 0~15 位。16位
    	dw	%1 & FFFFh															; 段基址的第 0~15 位。16位。
    	db	(%1 & FF0000h) >> 16										; 段基址的第 16~23 位。8位。
    	db	%3 & FFh																; 段屬性的第 0~7 位。48位。
    	db	(%2 & F0000) | (%3 >> 8) 								; 段界限的第 16~20 位 和 段屬性的第 8~11 位。56位。
    	db	%1 >> 24																; 段基址的第 24~31 位。8位。
    %endmacro
    

    使用這個宏創建一個描述符,代碼如下:

    DESC_VIDEO:	Descriptor	0B8000h		0ffff			0
    

    段屬性是隨便設置的。描述符的段屬性比較復雜。作者暫時沒有弄清楚。

    路漫漫其修遠兮,吾將上下而求索。

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有