內(nèi)存尋址
曾經(jīng)有一個(gè)叫“阿蘭.圖靈”的天才,它設(shè)想出了一種簡(jiǎn)單但運(yùn)算能力幾乎無(wú)限發(fā)達(dá)的理想機(jī)器——這可不是一個(gè)具體的機(jī)械玩藝,而是一個(gè)思想模型——用來(lái)計(jì)算能想象得到的所有可計(jì)算函數(shù)。這個(gè)有趣的機(jī)器由一個(gè)控制器,一個(gè)讀寫(xiě)頭和一條假設(shè)兩端無(wú)限長(zhǎng)的帶子組成。工作帶好比存儲(chǔ)器,被劃分成大小相同的格子,每格上可寫(xiě)一個(gè)字母,讀寫(xiě)頭可以在工作帶上隨意移動(dòng),而控制器可以要求讀寫(xiě)頭讀取其下方工作帶上的字母。
你可千萬(wàn)別覺(jué)得這個(gè)機(jī)器傻得可愛(ài),它可是當(dāng)代馮.諾依曼體系計(jì)算機(jī)的理論鼻祖。它帶來(lái)的“數(shù)據(jù)連續(xù)存儲(chǔ)和選擇讀取思想”可是目前我們使用的幾乎所有機(jī)器運(yùn)行背后的靈魂。計(jì)算機(jī)體系結(jié)構(gòu)中的核心問(wèn)題之一就是如何有效地進(jìn)行內(nèi)存尋址,因?yàn)樗羞\(yùn)算的前提都是先要從內(nèi)存中取得數(shù)據(jù),所以內(nèi)存尋址技術(shù)從某種程度上代表了了計(jì)算機(jī)技術(shù)。
下面就開(kāi)始一起聊聊關(guān)于尋址的故事。
馮.諾依曼體系計(jì)算機(jī)系統(tǒng)由運(yùn)算器、存儲(chǔ)器、控制器、輸入設(shè)備、輸出設(shè)備五大部件組成。運(yùn)算器就是我們熟知的CPU中的AUL(算術(shù)邏輯單元),存儲(chǔ)器是內(nèi)存,控制器是CPU中的控制單元;輸入設(shè)備就是我們的鼠標(biāo)鍵盤等;輸出設(shè)備就是顯示器,打印機(jī)等。
計(jì)算機(jī)的內(nèi)存尋址技術(shù)和世界上的其它事物一樣都經(jīng)歷了由簡(jiǎn)單到復(fù)雜,由笨拙到優(yōu)雅的過(guò)程。自我聽(tīng)說(shuō)計(jì)算機(jī)到今天,內(nèi)存尋址方法發(fā)生了幾次決定性的變革(“史前”的內(nèi)存尋址方法我連資料都沒(méi)由找到,真是無(wú)據(jù)可查了!),而每次變革都帶來(lái)了軟件技術(shù)的發(fā)展注入了新鮮血液。
讓我們沿著Intel公司的腳步來(lái)回顧一下歷史吧!(我實(shí)在沒(méi)機(jī)會(huì)接觸除Intel以外的處理器!!!)
20年前intel推出了一款8位處理器——8080,它有1個(gè)主累加器(寄存器A)和6個(gè)次累加器(寄存器B,C,D,E,H和L),幾個(gè)次累加器可以配對(duì)(如組成BC, DE或HL)使用來(lái)訪問(wèn)16位的內(nèi)存地址,也就是說(shuō)8080可訪問(wèn)到64K內(nèi)的地址空間。另外那時(shí)還沒(méi)有段的概念,訪問(wèn)內(nèi)存都要通過(guò)絕對(duì)地址,因此程序中的地址必須進(jìn)行硬編碼,而且也難以重定位,因此當(dāng)時(shí)的軟件大都是些可控性弱,結(jié)構(gòu)簡(jiǎn)陋,數(shù)據(jù)處理量小的工控程序。
人類從來(lái)都是不斷前進(jìn)的,很快幾年后intel就開(kāi)發(fā)出了16位的新處理器——8086,這便是內(nèi)存尋址的第一次飛躍。
8086處理器引入了一個(gè)重要概念——段。段描述了一塊有限的內(nèi)存區(qū)域,區(qū)域的起始位置存在專門的寄存器(段寄存器)中。另外8086處理器可以尋址到
系統(tǒng)所需要作的僅僅是:把16位的段地址左移動(dòng)4位后,再與16位的偏移量相加便可獲得一個(gè)20位的內(nèi)存地址,見(jiàn)圖1
圖 1
Intel內(nèi)存地址的描述形式也很貼近上圖,采用了“段地址:偏移量”的形式來(lái)描述內(nèi)存地址,比如A815:CF2D就代表段首地址在A815,段內(nèi)偏移位CF2D。
為了支持段機(jī)制,8086為程序使用的代碼段,數(shù)據(jù)段,堆棧段分別提供了專門的16位寄存器CS,DS和SS,此外還給內(nèi)存和字符串拷貝操作留下了一個(gè)目的段寄存器:ES。
段式內(nèi)存管理帶來(lái)了顯而易見(jiàn)的優(yōu)勢(shì)——程序的地址不再需要硬編碼了,調(diào)試錯(cuò)誤也更容易定位了,更可貴的是支持更大的內(nèi)存地址。程序員開(kāi)始獲得了自由。
人們的欲望在繼續(xù)膨脹。intel的80286處理器于1982年問(wèn)世了,它的地址總線位數(shù)增加到了24位,因此可以訪問(wèn)到
為了和過(guò)去兼容,80286內(nèi)存尋址可以以兩種方式進(jìn)行,一種是先進(jìn)的保護(hù)模式,另一種是老式的8086方式,被成為實(shí)模式。啟動(dòng)時(shí)候處理器處于實(shí)模式只能訪問(wèn)
真正的第二次內(nèi)存尋址飛躍發(fā)生在80386身上,它近乎完美的設(shè)計(jì)將計(jì)算機(jī)技術(shù)推向了一個(gè)新高度.
80386的地址總線擴(kuò)展到了32位,可尋址空間一下擴(kuò)充為
保護(hù)模式真得是太精妙了,我恨不得用專門用一本書(shū)來(lái)討論它,但即使那樣我也擔(dān)心不能真正觸其精華。不過(guò)還是借用那句老話”簡(jiǎn)單就是美麗”,我爭(zhēng)取用最小的篇幅揭示保護(hù)模式的真實(shí)面目。
保護(hù)模式和實(shí)模式好比一對(duì)孿生兄弟,它們外貌很像,從程序角度來(lái)看幾乎看不出什么區(qū)別,它們都是通過(guò)段寄存器去訪問(wèn)內(nèi)存地址,都通過(guò)中斷和設(shè)備驅(qū)動(dòng)程序來(lái)操作硬件,表面上能感覺(jué)得到的差異就是保護(hù)模式能訪問(wèn)的空間是
但實(shí)際上保護(hù)模式和實(shí)模式采用了兩種截然不同的思路,保護(hù)模式帶來(lái)的最可貴的優(yōu)點(diǎn)不是單純的擴(kuò)大了內(nèi)存尋址范圍,而是對(duì)內(nèi)存尋址從機(jī)制上提供了保護(hù),將系統(tǒng)的執(zhí)行空間按權(quán)限進(jìn)行了化分。
這種劃分到底會(huì)帶來(lái)那些好處啦? 我們來(lái)推敲一下吧。
如果你的機(jī)器只允許一個(gè)任務(wù)使用系統(tǒng)資源,比如說(shuō)系統(tǒng)內(nèi)存,那么你完全不需要保護(hù)資源,因?yàn)橄到y(tǒng)中再?zèng)]有什么值得你去偷窺的東西了,更別說(shuō)去破壞什么了。
可惜那樣的時(shí)代已經(jīng)一去不復(fù)返了,如今的系統(tǒng)需要支持多個(gè)用戶同時(shí)運(yùn)行多個(gè)任務(wù)。為了防止你去偷看別人的任務(wù),或惡意或由于你的荒唐行為而破壞別人的任務(wù),系統(tǒng)有責(zé)任將每個(gè)任務(wù)隔離開(kāi)來(lái),讓大家各自運(yùn)行在不同的空間,免收干擾。這就是保護(hù)的第一個(gè)方面——任務(wù)間保護(hù),要做到任務(wù)間保護(hù)需要借助虛擬內(nèi)存技術(shù)(我們后面分析它),其基礎(chǔ)之一就是保護(hù)模式。
除了任務(wù)間保護(hù)外,另一個(gè)必須保護(hù)的東西就是操作系統(tǒng)本身,它可是資源調(diào)配的首腦呀!決不能讓你有機(jī)可承,擅自進(jìn)入。必須有一道鐵絲網(wǎng),將你和操作系統(tǒng)隔離開(kāi),使你不得越雷池一步。要想拉起這道鐵絲網(wǎng),就需要借助保護(hù)模式中的特權(quán)級(jí)機(jī)制。操作系統(tǒng)放在高特權(quán)級(jí)里,你的任務(wù)被放在低特權(quán)級(jí)里。你沒(méi)有權(quán)利去偷看操作系統(tǒng)的內(nèi)容。有什么要求只能請(qǐng)示“領(lǐng)導(dǎo)”(就是保護(hù)機(jī)制),獲得拼準(zhǔn)后才能給你提供服務(wù)。這點(diǎn)可謂是保護(hù)模式的最直接應(yīng)用。
80386之所以能有變化多端的保護(hù)手段,追其根本源自保護(hù)模式下內(nèi)存尋址方式發(fā)生革命。傳統(tǒng)上我們知道段方式尋址時(shí),是直接從段寄存器中取得的段的首地址,但是在保護(hù)模式中是要多經(jīng)過(guò)一次檢查手續(xù)才能獲得想要的段地址。
這里可千萬(wàn)別再說(shuō)“簡(jiǎn)單就是美了”,多了這一次中間倒手過(guò)程可是保護(hù)模式下尋址的關(guān)鍵技術(shù)所在呀。倒手的原因我想大概是因?yàn)?,雖然80386有的通用寄存器(EAX,EDI等等)被擴(kuò)充倒了32位,但是其中的段寄存器(DS,ES等)仍然只有16位,顯然不可能再用16位的段寄存器直接存放
線性地址屬于中間地址,它還需要一次轉(zhuǎn)換才能映射到實(shí)際的物理地址上(下面會(huì)看到)。線性地址長(zhǎng)成的空間稱為線性空間,它和物理地址空間結(jié)構(gòu)想同,都為32位,最大可達(dá)
這個(gè)索引指針被稱作是段選擇子(見(jiàn)圖2),它共有16位,其中14位用來(lái)作為索引,另外2位(RPL)用來(lái)作描述請(qǐng)求特權(quán)級(jí)。通過(guò)索引從表中獲得的信息,被稱為段描述符,它含有段的相關(guān)地址信息等。
改變尋址方法的另一個(gè)原因主要是為了完成保護(hù)使命。多用戶多任務(wù)環(huán)境下,內(nèi)存尋地工作不再是簡(jiǎn)單地取得32位的內(nèi)存地址就可以直接不假思索地放到地址總線上去了讀寫(xiě)內(nèi)存了,此刻必須先要對(duì)需訪問(wèn)的地址進(jìn)行合法性檢查,看看訪問(wèn)者是不是有權(quán)利去訪問(wèn)它要求的地址。如果發(fā)現(xiàn)有非法訪問(wèn)企圖,則立刻阻止(CPU會(huì)產(chǎn)生一個(gè)一異常)這種危險(xiǎn)行為。讀到這里,多數(shù)的朋友一定要問(wèn),靠什么進(jìn)行檢查請(qǐng)求的合法性呢?更細(xì)心的朋友還會(huì)繼續(xù)問(wèn),檢查需要什么信息?這些信息放在那里?
考慮到尋址過(guò)程和合法性檢測(cè)過(guò)程需要在同一現(xiàn)場(chǎng)一起進(jìn)行,所以最理想是能把段地址信息和檢測(cè)合法性用到的屬性信息能放在一起(需要的空間更大了),于是系統(tǒng)設(shè)計(jì)師門便把屬性信息和段的基地址和界限都柔和在了一起,形成了一個(gè)新的信息單元——段描述符號(hào),它整整占用了8個(gè)字節(jié)。顯然寄存器太小,不夠存放段描述符,所以段描述符都被統(tǒng)一存在專門的系統(tǒng)段描述符號(hào)表中(GTD或LDT)保存。
說(shuō)到這里,聰明的朋友可能已經(jīng)能大概猜出段描述符表中的內(nèi)容是什么了。內(nèi)容里一定包含了段基地址、短的大小信息、段的屬性信系,而且在屬性信息里包含了還有和訪問(wèn)權(quán)限有關(guān)的信息。的確如此,下面圖示描述了段描述符的詳細(xì)信息,其中和保護(hù)關(guān)心最大的信息要數(shù)DPL了(見(jiàn)圖3)。
這種間接尋址方式不僅體現(xiàn)在普通任務(wù)尋址上,而且對(duì)于中斷處理同樣適用。傳統(tǒng)上中斷處理查詢方法是在中斷產(chǎn)生后,CPU會(huì)在中斷向量表中搜索中斷服務(wù)例程(ISR)的地址,地址形式還是段+偏移量。在保護(hù)模式中中斷產(chǎn)生后,CPU會(huì)從中斷描述符表(IDT)中根據(jù)中斷號(hào)取得中斷服務(wù)例程的段選擇子和偏移量,然后通過(guò)段選擇子從段描述附表(GDT)中獲得ISR的段信息再結(jié)合偏移量得到需要的實(shí)際物理地址。
中斷尋址過(guò)程如圖4
計(jì)算機(jī)世界和人類世界一樣最初是沒(méi)有等級(jí)之分的,但當(dāng)人類社會(huì)物質(zhì)文明逐步發(fā)達(dá)后,等級(jí)也隨之而來(lái)了;同樣當(dāng)計(jì)算機(jī)上的應(yīng)用軟件越來(lái)月豐富后,這個(gè)虛擬世界也逐漸形成了級(jí)別等級(jí)。我們不去評(píng)價(jià)人類社會(huì)等級(jí)制度,我們只來(lái)看看計(jì)算機(jī)世界中的等級(jí)制度,而且只陷于保護(hù)模式中的等級(jí)制度。
80386中共規(guī)定有4個(gè)特權(quán)級(jí),由0到3。0級(jí)別權(quán)限最高,3級(jí)最小。標(biāo)準(zhǔn)的作法是將操作系統(tǒng)核心運(yùn)行在0級(jí),應(yīng)用程序運(yùn)行其它幾個(gè)低級(jí)別。不過(guò)為了簡(jiǎn)化操作,往往只會(huì)用到0和3兩個(gè)級(jí)別。80386中的每個(gè)段描述符號(hào)中都有DPL字段,它規(guī)定了訪問(wèn)該段的最低特權(quán)級(jí),只用高于次特權(quán)級(jí)別的程序能有權(quán)訪問(wèn)它。所以在訪問(wèn)內(nèi)存地址時(shí)要將當(dāng)前特權(quán)級(jí)(CPL,一般來(lái)說(shuō)就是當(dāng)前代碼段的特權(quán)級(jí)別)和被訪問(wèn)段的特權(quán)級(jí)別比較,如果大于等于才允許訪問(wèn)。
處理當(dāng)前特權(quán)級(jí)別和段的特權(quán)級(jí)別外,有時(shí)還需要使用請(qǐng)求特權(quán)級(jí)別(RPL),這個(gè)子段出自段選擇字,主要用來(lái)輔助特權(quán)保護(hù)。比如可以在訪問(wèn)某個(gè)段時(shí),指定其請(qǐng)求特權(quán)級(jí),那么特權(quán)檢查時(shí),規(guī)則變?yōu)閷?span lang="EN-US" twffan="done">RPL和CPL中特權(quán)更高的那個(gè)和被訪問(wèn)段的DPL比較。例如,操作系統(tǒng)中的某個(gè)例程會(huì)把一些資料寫(xiě)到用戶段中。若沒(méi)有特別檢查,那么用戶可以把一個(gè) DPL為 0 的 段(用戶程序不能存取它)傳到操作系統(tǒng)處理例程中,因?yàn)橄到y(tǒng)例程有全權(quán)寫(xiě)入DPL為0的段,因此用戶程序就可以破壞該段中的資料了。為了避免這個(gè)問(wèn)題,系統(tǒng) API 在存取用戶傳入的段時(shí),可以先把該段選擇子的 RPL設(shè)定成和用戶程序的 CPL 相同,就不會(huì)意外寫(xiě)入原先用戶無(wú)權(quán)存取的段了。 (
但RPL在linux好像沒(méi)被怎么用到)
虛擬內(nèi)存可是個(gè)怎么強(qiáng)調(diào)也不過(guò)分的概念,它的存在極大地方便了程序設(shè)計(jì)任務(wù),徹底解放了程序員的手腳。下面我們就看看虛擬內(nèi)存的作用以及如何在存儲(chǔ)管理機(jī)制的基礎(chǔ)上實(shí)現(xiàn)它。
我們知道程序代碼和數(shù)據(jù)必須駐留在內(nèi)存中才能得以運(yùn)行,然而系統(tǒng)內(nèi)存數(shù)量很有限,往往不能容納一個(gè)完整程序的所有代碼和數(shù)據(jù),更何況在多任務(wù)系統(tǒng)中,可能需要同時(shí)打開(kāi)子處理程序,畫(huà)圖程序,瀏覽器等很多任務(wù),想讓內(nèi)存駐留所有這些程序顯然不大可能。因此我們能首先能想到的就是將程序分割成小分,只讓當(dāng)前系統(tǒng)運(yùn)行它所有需要的那部分留在內(nèi)存,其它部分都留在硬盤。當(dāng)系統(tǒng)處理完當(dāng)前任務(wù)片段后,再?gòu)耐獯嬷姓{(diào)入下一個(gè)待運(yùn)行的任務(wù)片段。的確老式系統(tǒng)的確這樣處理大任務(wù),而且這個(gè)工作是由程序員自行完成。但是隨之程序語(yǔ)源越來(lái)越高級(jí),程序員對(duì)系統(tǒng)體系的依賴程度降低了,很少有程序員能非常清楚的駕馭系統(tǒng)體系了,因此放手讓程序員負(fù)責(zé)將程序片段化和按需調(diào)入輕則降低效率,重則使得機(jī)器崩潰;再一個(gè)原因是隨程序越來(lái)越豐富,程序行為幾乎無(wú)法準(zhǔn)確預(yù)測(cè),程序員自己都很難判斷下一步需要載入那段程序。因此很難再靠預(yù)見(jiàn)性靜態(tài)分配固定大小的內(nèi)存,然后再機(jī)械地輪換程序片進(jìn)內(nèi)存執(zhí)行。系統(tǒng)必須采取一種能按需分配,不要程序員干預(yù)地新技術(shù)。
虛擬內(nèi)存[1]技術(shù)就是一種由操作系統(tǒng)接管的按需動(dòng)態(tài)內(nèi)存分配方法,它允許程序不知不覺(jué)種使用大于實(shí)際物理的存儲(chǔ)空間(其實(shí)是將程序需要的存儲(chǔ)空間以頁(yè)的形式分散存儲(chǔ)在物理內(nèi)存和磁盤上),所以說(shuō)虛擬內(nèi)存徹底解放了程序員,從此程序員不用過(guò)分關(guān)心程序大小和載入,可以自由編寫(xiě)程序了,繁瑣的事情都交給操作系統(tǒng)去作吧。
虛擬內(nèi)存是將系統(tǒng)硬盤空間和系統(tǒng)實(shí)際內(nèi)存聯(lián)合在一起為進(jìn)程使用,給進(jìn)程提供了一個(gè)比內(nèi)存大的多的虛擬空間。在程序運(yùn)行時(shí),只把虛擬地址空間的一小部分映射到內(nèi)存,其余都存儲(chǔ)在硬盤上(也就是說(shuō)程序虛擬空間就等于實(shí)際物理內(nèi)存加部分硬盤空間)。當(dāng)訪問(wèn)被訪問(wèn)的虛擬地址的不在內(nèi)存時(shí),則說(shuō)明該地址未被映射到內(nèi)存,而是被存貯在硬盤中,因此需要的虛擬存儲(chǔ)地址被隨即調(diào)入到內(nèi)存;同時(shí)當(dāng)系統(tǒng)內(nèi)存緊張時(shí),也可以把當(dāng)前不用的虛擬存儲(chǔ)空間換出到硬盤,來(lái)騰出物理內(nèi)存空間。系統(tǒng)如此周而復(fù)始地運(yùn)轉(zhuǎn)——換入、換出,而用戶幾乎無(wú)法查覺(jué),這都是拜虛擬內(nèi)存機(jī)制所賜。
Linux的swap分區(qū)就是硬盤專門為虛擬存儲(chǔ)空間預(yù)留的空間。經(jīng)驗(yàn)大小應(yīng)該是內(nèi)存的兩倍左右。有興趣的話可以使用 swapon -s 查看交換分區(qū)大小,還可以用vmstat 查看當(dāng)前每秒換入換出的數(shù)據(jù)大小(在si/so字段下)
大道理很好理解,無(wú)非是用內(nèi)存和硬盤空間合成為虛擬內(nèi)存空間。但是這一過(guò)程中反復(fù)運(yùn)行的地址映射(虛擬地址映射到物理地址)和虛擬地址換入換出卻值得仔細(xì)推敲。系統(tǒng)到底是怎么樣吧虛擬地址映射到物理地址上的呢??jī)?nèi)存又如何能不斷的和硬盤之間換入換出虛擬地址呢?
利用段機(jī)制能否回答上述問(wèn)題呢?我們上面提到過(guò)邏輯地址通過(guò)段機(jī)制后變?yōu)橐粋€(gè)32位的地址,足以覆蓋 因?yàn)槭褂?/span>頁(yè)機(jī)制的原因,通過(guò)段機(jī)制轉(zhuǎn)換得到的地址僅僅是作為一個(gè)中間地址——線性地址了,該地址不代表實(shí)際物理地址,而是代表整個(gè)進(jìn)程的虛擬空間地址。在線性地址的基礎(chǔ)上,頁(yè)機(jī)制接著會(huì)處理線性地址映射:當(dāng)需要的線性地址(虛擬空間地址)不在內(nèi)存時(shí),便以頁(yè)為單位從磁盤中調(diào)入需要的虛擬內(nèi)存;當(dāng)內(nèi)存不夠時(shí),又會(huì)以頁(yè)為單位把內(nèi)存中虛擬空間的換出到磁盤上。可見(jiàn)利用頁(yè)來(lái)管理內(nèi)存和磁盤(虛擬內(nèi)存)大大方便了內(nèi)存管理的工作。毫無(wú)疑問(wèn)頁(yè)機(jī)制是虛擬內(nèi)存管理簡(jiǎn)直是“天配”。 使用頁(yè)機(jī)制, 前面我們提到了線性地址是32位。它其中高20位是對(duì)頁(yè)表的索引,低12位則給出了頁(yè)面中的偏移。線性地址經(jīng)過(guò)頁(yè)表找到頁(yè)框基地址后和低12位偏移量相加就形成了最終需要的物理地址了。 在實(shí)際使用中,并非所有頁(yè)表項(xiàng)都是被存放在一個(gè)大頁(yè)表里,因?yàn)槊總€(gè)頁(yè)表項(xiàng)4字節(jié),如果要在一個(gè)表中存放2的20次方個(gè)頁(yè)表項(xiàng),就需要 兩級(jí)頁(yè)表搜索如同看章回小說(shuō),先找到在那一章里,然后在找在該章下那一節(jié)。具體過(guò)程看看下圖5。 [1] .之所以稱為虛擬內(nèi)存是和系統(tǒng)中的邏輯內(nèi)存和物理內(nèi)存而言的,邏輯內(nèi)存是站在進(jìn)程角度看到的內(nèi)存,因此是程序員關(guān)心的內(nèi)容。而物理內(nèi)存是站在處理器角度看到的內(nèi)存,由操作系統(tǒng)負(fù)責(zé)管理。虛擬內(nèi)存可以說(shuō)是這映射這兩種不同視角內(nèi)存的一個(gè)技術(shù)手段。 綜上所述。地址轉(zhuǎn)換工作需要兩種技術(shù),一是段機(jī)制,二是頁(yè)機(jī)制。段機(jī)制處理邏輯地址向線性地址映;頁(yè)機(jī)制則負(fù)責(zé)把線性地址映射為物理地址。兩級(jí)映射一同完成了從程序員看到的邏輯地址轉(zhuǎn)換到處理器看到的物理地址這一艱巨任務(wù)。 你可以將這兩種機(jī)制分別比作一個(gè)地址轉(zhuǎn)換函數(shù),段機(jī)制的變量是邏輯地址,函數(shù)值是線性地址;頁(yè)機(jī)制的變量是線性地址,函數(shù)值是物理地址。地址轉(zhuǎn)換過(guò)程如下所示。 邏輯地址——(段函數(shù))——>線性地址——(頁(yè)函數(shù))——>物理地址。 雖然段機(jī)制和頁(yè)機(jī)制都參與映射,但它們分工不同,而且相互獨(dú)立互不干擾,彼此之間不必知道對(duì)方是否存在。 說(shuō)了這么多道理,下面我們結(jié)合Linux實(shí)例簡(jiǎn)要地看看段頁(yè)機(jī)制如何使用。 段機(jī)制在Linux里用得有限,并沒(méi)有被完全利用。每個(gè)任務(wù)并未分別安排各自獨(dú)立的數(shù)據(jù)段,代碼段,而是僅僅最低限度的利用段機(jī)制來(lái)隔離用戶數(shù)據(jù)和系統(tǒng)數(shù)據(jù)——Linux只安排了四個(gè)范圍一樣的段,內(nèi)核數(shù)據(jù)段,內(nèi)核代碼段,用戶數(shù)據(jù)段,用戶代碼段,它們都覆蓋0 每個(gè)用戶進(jìn)程都可以看到 說(shuō)到特權(quán)切換,就離不開(kāi)任務(wù)門,陷阱門/中斷門等概念。陷阱門和中斷門是在發(fā)生陷阱和中斷時(shí),進(jìn)入內(nèi)核空間的通道。調(diào)用門是用戶空間程序相互訪問(wèn)時(shí)所需要的通道,任務(wù)門比較特殊,它不含如何地址,而是服務(wù)于任務(wù)切換(但linux任務(wù)切換時(shí)并未真正采用它,它太麻煩了)。 對(duì)于各種門系統(tǒng)都會(huì)有對(duì)應(yīng)的門描述符,和段描述符結(jié)構(gòu)類似,門描述符也是由對(duì)應(yīng)的門選擇字索引,并且最終會(huì)產(chǎn)生一個(gè)指向特定段內(nèi)偏移地址的指針。這個(gè)指針就指向的是將要進(jìn)入的入口。利用門的目的就是保證入口可控,不至于進(jìn)入到內(nèi)核中不該訪問(wèn)的位置(回憶前面講到的中斷服務(wù)程序?qū)ぶ罚渲袕闹袛嗝枋龇?hào)表中獲得的就是中斷門的描述符,而描述符則制定了具體的入口位置)。 我們前面大概談了談為什么要使用分頁(yè),這里看看linux中如何使用分頁(yè)。 Linux中每個(gè)進(jìn)程都會(huì)有個(gè)自的不同的頁(yè)表,也就是說(shuō)進(jìn)程的映射函數(shù)互不相同,保證每個(gè)進(jìn)程虛擬地址不會(huì)映射到相同的物理地址上。這是因?yàn)檫M(jìn)程之間必須相互獨(dú)立,各自的數(shù)據(jù)必須隔離,防止信息泄漏。 另外需要注意的是,內(nèi)核作為必須保護(hù)的單獨(dú)部分,它有自己獨(dú)立的頁(yè)表來(lái)映射內(nèi)核空間(并非全部空間,僅僅是物理內(nèi)存大小的空間),該頁(yè)表(swapper_pg_dir)被靜態(tài)分配,它只來(lái)映射內(nèi)核空間(swapper_pg_dir只用到768項(xiàng)以后的項(xiàng)——768個(gè)頁(yè)目錄可映射 那么在用戶進(jìn)程需要訪問(wèn)內(nèi)核空間時(shí)如何作呢? Linux采用了個(gè)巧妙的方法:用戶進(jìn)程頁(yè)表的前768項(xiàng)映射進(jìn)程空間(< Linux分段段策略
Linux中的分頁(yè)策略
聯(lián)系客服