我先告訴你寄存器是什么。

寄存器是一種物理存儲(chǔ)元件,只不過(guò)它是比一般的存儲(chǔ)介質(zhì)要快,能夠跟上cpu的步伐,所以在cpu內(nèi)部有好多這樣的寄存器用來(lái)給cpu存取數(shù)據(jù)。

先簡(jiǎn)短說(shuō)這一兩句,暫時(shí)離開(kāi)一下主題,咱們先看看相對(duì)熟悉一些的概念——緩存。

緩存也是一項(xiàng)非常偉大的發(fā)明,成功解決了速度不匹配設(shè)備之間的數(shù)據(jù)傳輸,并且在一般情況下,IO是整個(gè)系統(tǒng)的瓶頸,緩存的出現(xiàn),有效減少了低速I(mǎi)O設(shè)備的訪(fǎng)問(wèn)頻率,從而大幅度的提升了速度。

大家對(duì)緩存一定不會(huì)陌生,生活中處處都是緩存的應(yīng)用。比如瀏覽器在請(qǐng)求一個(gè)域名的ip時(shí):

  1. 1瀏覽器內(nèi)部都有dns客戶(hù)端,它先查詢(xún)本地dns緩存中是否有該域名的ip,如果有就直接去訪(fǎng)問(wèn)該ip。如果沒(méi)有,該dns客戶(hù)端先要查找自己主機(jī)所設(shè)置的dns服務(wù)器,然后去該dns服務(wù)器去查詢(xún)ip。
  2. 如果該dns服務(wù)器本地緩存中有該域名的A記錄(域名與ip地址的對(duì)應(yīng)記錄),則直接返回給瀏覽器中的dns客戶(hù)端。沒(méi)有該域名的A記錄,就通過(guò)遞歸的方式向上詢(xún)問(wèn)其它dns服務(wù)器,也許問(wèn)到了根dns服務(wù)器才找到了答案。于是這路上所有被詢(xún)問(wèn)過(guò)的dns服務(wù)器,都將此域名對(duì)應(yīng)的A記錄緩存到自己的cache中,以備下次再有相同域名查詢(xún)時(shí)好直接返回。
  3. 瀏覽器中的dns客戶(hù)端得到此域名的ip地址后,也將該域名和ip放在自己的緩存中,以備下次用戶(hù)再鍵入同一域名時(shí),避免再查一次ip。
  4. 瀏覽器開(kāi)始通過(guò)網(wǎng)絡(luò)用http協(xié)議訪(fǎng)問(wèn)該ip地址的80端口(默認(rèn)是80端口,除非特別指定)。
  5. 一般情況下該ip對(duì)應(yīng)的設(shè)備不是最終的web服務(wù)器,很少有人把web服務(wù)器直接暴露在公網(wǎng)。假設(shè)該ip對(duì)應(yīng)的設(shè)備是臺(tái)網(wǎng)關(guān)(一般是硬件路由設(shè)備),該網(wǎng)關(guān)檢查本地緩存中是否有相關(guān)web服務(wù)器的緩存,若有則直接將該http請(qǐng)求分配給緩存中的web服務(wù)器。否則從服務(wù)器列表中重新分配一臺(tái)web服務(wù)器,將該http請(qǐng)求轉(zhuǎn)發(fā)給該web服務(wù)器處理。隨后將該web服務(wù)器的ip地址(一般是內(nèi)網(wǎng)地址)和端口號(hào)緩存起來(lái),以備下次該用戶(hù)的請(qǐng)求到來(lái)時(shí),依然給該web服務(wù)器。有的網(wǎng)關(guān)可以識(shí)別用戶(hù)cookie信息,從而將可以請(qǐng)求再次落到上一個(gè)請(qǐng)求的web服務(wù)器上。
  6. web服務(wù)器拿到請(qǐng)求后,如果是靜態(tài)請(qǐng)求,先檢查自己的緩存中是否有該頁(yè)面的記錄,否則直接從硬盤(pán)上取出頁(yè)面,將其返回后,再存入本地靜態(tài)緩存中。如果動(dòng)態(tài)請(qǐng)求,先交給自己的cgi去處理。
  7. cgi拿到請(qǐng)求后,先檢查自己的緩存系統(tǒng)如memcache,如果緩存中沒(méi)有,與數(shù)據(jù)庫(kù)建立連接,向數(shù)據(jù)庫(kù)發(fā)出請(qǐng)求。
  8. 數(shù)據(jù)庫(kù)也是先檢查自己的緩存,若沒(méi)有結(jié)果集,則從表中檢索到數(shù)據(jù)后返回,并將結(jié)果集緩存起來(lái)。
  9. cgi拿到數(shù)據(jù)后,返回給web服務(wù)器。并將數(shù)據(jù)緩存到memcache中。
  10. web服務(wù)器拿到了數(shù)據(jù)后,將數(shù)據(jù)返回給網(wǎng)關(guān)。由于是動(dòng)態(tài)數(shù)據(jù),不需要緩存。
  11. 網(wǎng)關(guān)拿到數(shù)據(jù)后,直接返回給瀏覽器。
  12. 如果瀏覽器發(fā)現(xiàn)其中有靜態(tài)數(shù)據(jù),如圖片,也將靜態(tài)數(shù)據(jù)緩存到用戶(hù)的internet 臨時(shí)目錄。

您看,就這么一個(gè)不起眼的網(wǎng)頁(yè)請(qǐng)求,就經(jīng)過(guò)了12步,幾乎每一步都要緩存結(jié)果,當(dāng)然每一層的緩存都有一定的失效時(shí)間,超過(guò)多少秒后就將緩存中的記錄置為無(wú)效。這其中還有另外一個(gè)術(shù)語(yǔ),如果緩存中恰好有需要的內(nèi)容,這就稱(chēng)為命中hit,否則稱(chēng)為缺失mis。

其實(shí)上面的緩存,我還沒(méi)說(shuō)全呢,硬件之間還有緩存呢,比如硬盤(pán)控制器和硬盤(pán)……得,您還是打住吧,我是來(lái)學(xué)操作系統(tǒng)的,您跟我說(shuō)這干嗎,還說(shuō)了12個(gè)步驟,這與我何干?

兄弟稍安誤燥,待小弟細(xì)細(xì)道來(lái)。前面所說(shuō)的各種緩存,是為了引出cpu中的緩存。cpu中的一級(jí)緩存L1,二級(jí)緩存L2,它們都是SRAM,即靜態(tài)隨機(jī)訪(fǎng)問(wèn)存儲(chǔ)器,它是最快的存儲(chǔ)器啦。也許您又說(shuō):“是啊,這個(gè)我知道,那又怎么樣?”

好啦不賣(mài)關(guān)子啦,也許您只聽(tīng)說(shuō)L1、L2、SRAM,但您可能不知道的是,SRAM是用寄存器來(lái)存儲(chǔ)數(shù)據(jù)的,這就是SRAM快的原因。而寄存器為什么快呢?原因是,寄存器是使用觸發(fā)器實(shí)現(xiàn)的,這也是一種存儲(chǔ)電路,工作速度極快,是納秒級(jí)別的,您想寄存器能不快嗎,這和cpu的速度是一個(gè)級(jí)別啦。硬件我也不是很了解,所以只能跟您說(shuō)到這了,點(diǎn)到為止,對(duì)于硬件背后的原理,咱們蜻蜓點(diǎn)水即可。

巧婦難為無(wú)米之炊,不管是指令還是數(shù)據(jù),cpu內(nèi)部總該有個(gè)地方存放它們,否則cpu這位巧婦連鍋都沒(méi)有,還怎么給大家燒一桌好菜呢。所以,寄存器是給cpu處理數(shù)據(jù)的場(chǎng)所。

到這里,大家心里應(yīng)該對(duì)寄存器有個(gè)感性認(rèn)識(shí)了,這樣學(xué)起來(lái),似乎看得見(jiàn)摸得著了。

cpu中的寄存器大致上分為兩大類(lèi):

  • λ 一類(lèi)是其內(nèi)部使用的,對(duì)程序員不可見(jiàn)。“是否可見(jiàn)”不是說(shuō)寄存器是否能看得見(jiàn),是指程序員是否能使用。cpu內(nèi)部有其自己的運(yùn)行機(jī)制,是按照某個(gè)預(yù)定框架進(jìn)行的,為了cpu能夠運(yùn)行下去,必然會(huì)有一些寄存器來(lái)做數(shù)據(jù)的支撐,給cpu內(nèi)部的數(shù)據(jù)提供存儲(chǔ)空間。這一部分對(duì)外是不可見(jiàn)的,我們無(wú)法使用它們。比如全局描述符表寄存器GDTR,中斷描述符表寄存器IDTR,局部描述符表寄存器LDTR,任務(wù)寄存器TR,控制寄存器CR0~3,指令指針寄存器IP,標(biāo)志寄存器flags,調(diào)試寄存器DR0~7。
  • λ 另一類(lèi)是對(duì)程序員可見(jiàn)的寄存器。我們進(jìn)行匯編語(yǔ)言程序設(shè)計(jì)時(shí),能夠直接操作的就是這些寄存器。如段寄存器,通用寄存器。

雖說(shuō)第一類(lèi)的程序是不可見(jiàn)寄存器,我們沒(méi)辦法直接使用,但它們中的一部分還得由咱們給初始化呢。比如全局描述符表寄存器GDTR,以后咱們還要通過(guò)lgdt指令為其指定全局描述符表的地址及偏移量。對(duì)于中斷描述符表寄存器IDTR,咱們也是要通過(guò)lidt指令為其指定中斷描述符表的地址。而局部描述符表寄存器LDTR,可以用lldt指令為其指定局部描述符表ldt(但我們效仿了現(xiàn)代操作系統(tǒng),未用局部描述符表ldt)。對(duì)于任務(wù)寄存器TR,我們也要用ltr指令為其在指定一個(gè)任務(wù)狀態(tài)段tss。對(duì)于flags寄存器,我們也有辦法設(shè)置它,系統(tǒng)提供了pushf和popf指令,分別用于將flags寄存器的內(nèi)容壓入棧,將棧中內(nèi)容彈到flags寄存器。額外說(shuō)一句,ldt和tss都位于gdt中。這些方面的內(nèi)容咱們?cè)趯W(xué)習(xí)保護(hù)模式后都會(huì)講到。

在實(shí)模式下,默認(rèn)用到的寄存器都是16位寬,咱們說(shuō)說(shuō)具體的寄存器吧。段寄存器是做啥的呢。說(shuō)到段寄存器存在的理由,得先說(shuō)到內(nèi)存訪(fǎng)問(wèn)機(jī)制。cpu是用“段基址:段內(nèi)偏移地址”的形式來(lái)訪(fǎng)問(wèn)內(nèi)存的,如果您對(duì)此訪(fǎng)存形式不了解,前面第0章中有解釋過(guò)分段,而且在下一節(jié)中也是講內(nèi)存分段的理由。您合理安排閱讀。

現(xiàn)在假設(shè)您已經(jīng)了解分段機(jī)制啦,上面提到的“段基址:段內(nèi)偏移地址”中的段基址,就是用段寄存器來(lái)存儲(chǔ)的,段寄存器的作用就是指定一片內(nèi)存的起始地址,故也稱(chēng)為段基址寄存器。盡管段基址在實(shí)模式下要乘以16,在保護(hù)模式下只是個(gè)選擇子(保護(hù)模式中會(huì)講),但其作用就是指定一片內(nèi)存的起始地址。而段內(nèi)偏移地址,顧名思義,僅僅相對(duì)于此起始地址的偏移量。

訪(fǎng)問(wèn)內(nèi)存,是要通過(guò)地址總線(xiàn),給地址總線(xiàn)一個(gè)數(shù)字(也就是地址),地址總線(xiàn)就能找到以該數(shù)字為地址的內(nèi)存??墒沁@個(gè)數(shù)字是哪來(lái)的呢?對(duì)于首次訪(fǎng)問(wèn)內(nèi)存之前,其內(nèi)存地址肯定是要放在與內(nèi)存不同的存儲(chǔ)介質(zhì)中更合適也更容易。如果用內(nèi)存來(lái)存儲(chǔ)內(nèi)存地址,首先訪(fǎng)問(wèn)該內(nèi)存就是個(gè)問(wèn)題,該內(nèi)存的地址是什么?這就跟先有雞還是先有蛋的本源問(wèn)題一樣了。您可能會(huì)有疑問(wèn),地址也只是個(gè)數(shù)字,把數(shù)字存放在內(nèi)存中有什么不行的。我這里所說(shuō)的并不是內(nèi)存尋址,您說(shuō)的這個(gè)數(shù)字只是該內(nèi)存單元中的內(nèi)容,這是內(nèi)存尋址,前提是您已經(jīng)給地址總線(xiàn)提交了保存該數(shù)字的內(nèi)存地址。我說(shuō)的是,提交給地址總線(xiàn)的地址,是從哪里獲得的。不知道我說(shuō)清楚了沒(méi)有,再舉個(gè)例子,我想用木材做一個(gè)船模,我不可能還用木質(zhì)工具去加工它,只能用鐵器等比木更硬的材料通過(guò)削、磨等方式將它加工出來(lái)。換在計(jì)算機(jī)中也一樣,訪(fǎng)問(wèn)內(nèi)存就要提供地址,初次訪(fǎng)問(wèn)內(nèi)存時(shí),該地址要么用立即數(shù),要么存儲(chǔ)在某個(gè)存儲(chǔ)器中能讓cpu取出來(lái)再訪(fǎng)問(wèn)內(nèi)存,肯定不能用內(nèi)存本身來(lái)存。由于寄存器比內(nèi)存更高級(jí),cpu更能接受,所以就用寄存器來(lái)存儲(chǔ)內(nèi)存地址。由于要指定的是內(nèi)存中的一段區(qū)域的起始地址,所以稱(chēng)之為段基址寄存器,也稱(chēng)段寄存器,無(wú)論是在實(shí)模式下還是保護(hù)模式下,它們都是16位寬。

下面就是實(shí)模式下的段寄存器

代碼段簡(jiǎn)而言之就是把所有指令都連續(xù)排放在一起,形成了一個(gè)全部都是指令的區(qū)域,里面存儲(chǔ)的是指令的操作碼及尋址方式等。該區(qū)域可以在硬盤(pán)上的文件中,也可以是被加載后的內(nèi)存中??傊且欢沃噶顓^(qū)域,它們內(nèi)部都是緊湊挨著的,內(nèi)容形式完全一樣,只是存放的介質(zhì)不一樣而已。代碼段寄存器CS就是用來(lái)指向內(nèi)存中這段指令區(qū)域的起始地址。具體程序分段的解釋?zhuān)梢?jiàn)第0章。

數(shù)據(jù)段和代碼段類(lèi)似,只是這段區(qū)域中的內(nèi)容不是指令而是純粹的數(shù)據(jù),也就是說(shuō)里面存儲(chǔ)的是程序運(yùn)行所需要的數(shù)據(jù),屬于指令的操作數(shù)。數(shù)據(jù)段寄存器DS便是用來(lái)指向此數(shù)據(jù)區(qū)域的起始地址。

棧段是在內(nèi)存中,硬盤(pán)文件中可真沒(méi)有。一般的棧段是由操作系統(tǒng)分配指定的,所以是屬于被加載到內(nèi)存后才有的。本章后面還會(huì)講棧,這里大家就先當(dāng)它是一段內(nèi)存區(qū)域就好。棧段寄存器SS就是用來(lái)指向此區(qū)域的起始地址。

代碼段、數(shù)據(jù)段、棧段寄存器從名字上就較容易理解,那三個(gè)附加段寄存器是干嗎的?其實(shí)就是多給大家提供幾個(gè)段寄存器用而已,多幾個(gè)寄存器用不是更好嗎,省得緊巴巴的,純粹是為了方便大家。

值得說(shuō)明的是,在16位cpu中,只有一個(gè)附加段寄存器——ES。而FS和GS附加段寄存器是在32位cpu中增加的。我們使用的是32位cpu,并不是說(shuō)32位cpu在實(shí)模式下的16位環(huán)境中就不能用FS和GS寄存器。32位的cpu是兼容16位cpu的特性,就像一個(gè)小學(xué)生也可以穿中學(xué)生的衣服一樣,無(wú)非是多用了個(gè)可用的資源。

IP寄存器是不可見(jiàn)寄存器,CS寄存器是可見(jiàn)寄存器。這兩個(gè)配合在一起后就是cpu的羅盤(pán),它們是給cpu導(dǎo)航用的。cpu執(zhí)行到何處,完成要聽(tīng)這兩個(gè)寄存器的安排。為什么要用兩個(gè)寄存器?因?yàn)橹噶钍窃趦?nèi)存中,訪(fǎng)問(wèn)內(nèi)存就要用“段:段內(nèi)偏移”的形式,所以CS寄存器用來(lái)存代碼段段基址,IP寄存器用來(lái)存儲(chǔ)代碼段段內(nèi)偏移地址,同CS寄存器一樣都是16位寬。

其實(shí)這兩個(gè)寄存器沒(méi)什么神奇的,并不是它們真的決定了cpu的航向,只是cpu的航向被存入了這兩個(gè)寄存器之中。之前說(shuō)過(guò)啦,指令在邏輯上是緊湊的,這樣cpu便能連續(xù)不斷的執(zhí)行下去,天荒地老,直到斷電。cpu執(zhí)行完一條指令后,順便就把下一條指令的內(nèi)存地址讀進(jìn)來(lái)。注意看,讀入的是下一條指令的內(nèi)存地址,這有兩個(gè)關(guān)鍵字,一個(gè)是內(nèi)存,一個(gè)是地址。剛剛說(shuō)過(guò)啦,是內(nèi)存就應(yīng)該用“段基址:段內(nèi)偏移地址”的機(jī)制來(lái)訪(fǎng)問(wèn)。是地址就該有地方存放。您想,即使是洗菜,菜也得先找個(gè)盤(pán)子或盆之類(lèi)的器具盛著再拿到水籠頭下沖洗。在x86體系架構(gòu)中,本著先滿(mǎn)足“段基址:段內(nèi)偏移”的形式,這個(gè)地址就分開(kāi)存到了代碼段CS寄存器和指令指針I(yè)P寄存器。在執(zhí)行當(dāng)前指令的同時(shí),在不跨段的情況下,cpu以“當(dāng)前IP寄存器中的值+當(dāng)前執(zhí)行指令的機(jī)器碼長(zhǎng)度”的和做為新的代碼段內(nèi)偏移地址,將其存入IP寄存器,再到該新地址處讀取指令并執(zhí)行。如果下一條指令需要跨段訪(fǎng)問(wèn),還要加載新的段基址到CS寄存器。此后,繼續(xù)重復(fù)以上“取址、執(zhí)行”的循環(huán)。

好啦,客官以后常來(lái)玩兒哦。

本節(jié)內(nèi)容摘自操作系統(tǒng)真象還原,請(qǐng)大家支持正版。

【再續(xù)】

1.《【ds為什么寄存器】一步步編寫(xiě)操作系統(tǒng) 12 代碼段、數(shù)據(jù)段、棧和cpu寄存器的關(guān)系》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識(shí),僅代表作者本人觀(guān)點(diǎn),與本網(wǎng)站無(wú)關(guān),侵刪請(qǐng)聯(lián)系頁(yè)腳下方聯(lián)系方式。

2.《【ds為什么寄存器】一步步編寫(xiě)操作系統(tǒng) 12 代碼段、數(shù)據(jù)段、棧和cpu寄存器的關(guān)系》僅供讀者參考,本網(wǎng)站未對(duì)該內(nèi)容進(jìn)行證實(shí),對(duì)其原創(chuàng)性、真實(shí)性、完整性、及時(shí)性不作任何保證。

3.文章轉(zhuǎn)載時(shí)請(qǐng)保留本站內(nèi)容來(lái)源地址,http://f99ss.com/auto/3089229.html