最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

一文徹底理解操作系統(tǒng):CPU與實(shí)模式

2023-04-10 17:22 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

對(duì)于人類來說,我們不喜歡拐彎抹角,喜歡更直接的東西,“有話直說”、“沒有中間商賺差價(jià)”、“簡(jiǎn)潔的設(shè)計(jì)”等等,然而對(duì)于計(jì)算機(jī),尤其是對(duì)內(nèi)存管理來說則恰恰相反,在這里"簡(jiǎn)潔"的設(shè)計(jì)往往不是好的設(shè)計(jì),這到底是什么意思呢?我們?cè)诤茉绲奈恼轮芯吞岬竭^,內(nèi)存從本質(zhì)上將非常簡(jiǎn)單,你可以將其想像成一個(gè)個(gè)的小盒子組成,每個(gè)小盒子要么能存儲(chǔ)1要么存儲(chǔ)0,每8個(gè)小盒子組成一個(gè)字節(jié)(8比特),每個(gè)字節(jié)都有一個(gè)唯一的地址,通過這個(gè)地址我們就能從相應(yīng)的一組小盒子取出這個(gè)比特。其它沒了。看到了吧,內(nèi)存本身其實(shí)是非常簡(jiǎn)單的,然而程序員以及程序使用內(nèi)存的方式又讓這個(gè)問題變得復(fù)雜起來,分析任何復(fù)雜問題都要抓住重點(diǎn)、抓住核心問題,那么這里的重點(diǎn)以及核心是什么呢?不賣關(guān)子,這里的核心在于兩個(gè)字:尋址,Addressing。一切都是圍繞尋址展開的。

尋址,最重要的就是尋址

什么是尋址 Addressing?所謂尋址就是找到內(nèi)存中某個(gè)我們需要的數(shù)據(jù)的方式。哪怕以我們平時(shí)去儲(chǔ)物柜取東西都有很多“尋址”方式:

  • 直接告訴我們一個(gè)編號(hào),我們拿到這個(gè)編號(hào)后按個(gè)去找,就像下面這張圖,我們需要找到東西在第15號(hào)儲(chǔ)物柜中,那么我們根據(jù)15這個(gè)地址就能找到第15號(hào)儲(chǔ)物柜。

  • 當(dāng)然我們也可以將儲(chǔ)物柜劃分區(qū)域,還是以剛才的儲(chǔ)物柜為例我們可以劃分為3個(gè)區(qū)域,當(dāng)我們需要找東西時(shí)告訴我們其在儲(chǔ)物柜的哪個(gè)區(qū)域,以及在該區(qū)域中的"偏移"是多少。

    以下圖為例我們需要的東西在第二個(gè)區(qū)域,區(qū)域內(nèi)的偏移為6(該區(qū)域中的第6個(gè)儲(chǔ)物柜)。

實(shí)際上,第一種更像是“絕對(duì)尋址”,什么意思呢?就是找到某個(gè)具體的儲(chǔ)物柜是根據(jù)一個(gè)“寫死的地址”(hardcode),很死板,第二種更像是相對(duì)尋址,稍顯靈活一些。怎么樣,你是不是感覺這兩種其實(shí)也沒什么區(qū)別嘛,的確,對(duì)于找儲(chǔ)物柜這個(gè)例子來說這兩種方式的確沒什么區(qū)別,但對(duì)于內(nèi)存來說就不太一樣了。

死板 vs 靈活

我們知道程序以及程序使用的數(shù)據(jù)編譯好后存放在磁盤上,運(yùn)行時(shí)要加載到內(nèi)存中,因此這里同樣存在尋址問題:我們需要根據(jù)內(nèi)存地址找到機(jī)器指令以及數(shù)據(jù),接下來假設(shè)有一個(gè)只有8字節(jié)大小的內(nèi)存和一個(gè)只有2字節(jié)機(jī)器指令的程序(無需關(guān)心實(shí)際意義):

這段2字節(jié)的代碼非常簡(jiǎn)單,其實(shí)就是一個(gè)無意義的while循環(huán),注意看這里的jmp這條指令,我們直接跳轉(zhuǎn)到內(nèi)存地址2,這就是一個(gè)寫死(hard code)的內(nèi)存地址,這就意味著我們必須把該程序加載到內(nèi)存地址為2的位置上:

否則這段指令根本沒有辦法運(yùn)行,比如我們把這段代碼加載到內(nèi)存地址6上去:

那么在執(zhí)行jmp 2時(shí)我們根本沒有辦法跳轉(zhuǎn)到add這行指令,有的同學(xué)可能覺得無所謂,不就是內(nèi)存地址寫死了嘛,好像也沒什么大不了的吧。如果一次只能運(yùn)行一個(gè)程序的確也沒什么大不了的,但對(duì)于操作系統(tǒng)最核心的功能之一:多任務(wù),也就是一次可以運(yùn)行多個(gè)程序來說這個(gè)方案簡(jiǎn)直行不通。在這種方案下你幾乎沒有辦法一次運(yùn)行多個(gè)程序,除非在運(yùn)行之前你給要運(yùn)行的這幾個(gè)程序劃定好區(qū)域,比如要運(yùn)行兩個(gè)程序A和B,A占用0~3這個(gè)區(qū)域的內(nèi)存;B占用4~6這個(gè)區(qū)域的內(nèi)存,對(duì)于現(xiàn)代程序員來說你能想象在程序運(yùn)行之前就需要給它劃定好區(qū)域嗎?顯然,這非常繁瑣,也容易出錯(cuò)。如果你在上世紀(jì)六七十年代寫代碼,面臨的大概就是這樣一種狀況。實(shí)際上這個(gè)問題的核心就在于重定位,程序使用的地址不能綁定在一個(gè)內(nèi)存區(qū)域上,需要足夠靈活,我們需要在不修改代碼的情況下把程序加載到任意內(nèi)存區(qū)域上運(yùn)行!想一想該怎么解決這個(gè)問題。作為程序員肯定和文件路徑打過交道,如果你能明白絕對(duì)路徑與相對(duì)路徑就能解決重定位問題。

絕對(duì)路徑與相對(duì)路徑

想一想絕對(duì)地址有什么問題?這個(gè)問題就好比你在程序中讀取一個(gè)絕對(duì)地址時(shí):

如果是你自己的計(jì)算機(jī)那么沒有問題,但如果這個(gè)程序在其它人的計(jì)算機(jī)上運(yùn)行就不一定了,因?yàn)槠渌说挠?jì)算機(jī)中不一定有這個(gè)路徑,這時(shí)該怎么辦呢?聰明的你一定知道,那就不要使用絕對(duì)路徑,而是使用相對(duì)路徑就可了:

其中./表示程序運(yùn)行時(shí)所在的路徑,這時(shí)不管這個(gè)程序在哪個(gè)路徑下運(yùn)行都能找到a.c這個(gè)文件,這時(shí)所在的目錄就成為了基準(zhǔn)。解決重定位這個(gè)問題也是同樣的道理,編程生成可執(zhí)行程序時(shí)不再使用絕對(duì)內(nèi)存地址,而是使用相對(duì)地址,怎么使用相對(duì)地址呢?相對(duì)于誰呢?很簡(jiǎn)單,相對(duì)于該程序被加載到的內(nèi)存起始地址。此時(shí)我們的jmp命令后面不再是一個(gè)絕對(duì)的內(nèi)存地址,而是一個(gè)相對(duì)地址:0,但畢竟向內(nèi)存發(fā)出讀寫指令時(shí)必須使用一個(gè)內(nèi)存地址,那么CPU執(zhí)行jmp 0時(shí)該怎樣將其轉(zhuǎn)為一個(gè)內(nèi)存地址呢?

很簡(jiǎn)單,因?yàn)檫@一段程序被加載到了內(nèi)存起始地址2,因此只需要用相對(duì)地址加上起始地址得到的就是真實(shí)的物理內(nèi)存地址:

物理地址 = 起始地址 + 相對(duì)地址

很簡(jiǎn)單吧,這樣不管這段程序被加載到了哪個(gè)內(nèi)存區(qū)域,只要我們知道起始地址那么總能計(jì)算出真實(shí)的物理內(nèi)存地址,重定位問題就可以這樣解決。實(shí)際上你會(huì)發(fā)現(xiàn),這個(gè)儲(chǔ)物柜的第二種尋址方式也沒有什么區(qū)別


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ??


分段式內(nèi)存管理

我們知道,程序的內(nèi)存從內(nèi)容上可以分為存放機(jī)器指令的代碼區(qū)域、存放全局變量的數(shù)據(jù)區(qū)域、保存函數(shù)運(yùn)行時(shí)信息的棧區(qū)等,顯然我們可以將程序按照這種劃分進(jìn)行分段管理,段內(nèi)使用相對(duì)地址,這樣無論這些段被加載到內(nèi)存的哪個(gè)區(qū)域我們都能方便的計(jì)算出正確的物理內(nèi)存地址。

我們將各個(gè)段在內(nèi)存中的起始地址放到專用的寄存器中,X86 CPU中有這樣幾個(gè)段寄存器,CS、DS、SS以及ES,這些寄存器有什么用呢?這幾個(gè)寄存器就用來存放各個(gè)段在內(nèi)存中的起始地址(暫且這樣理解,稍后你會(huì)發(fā)現(xiàn)這些寄存器的真實(shí)用法):

  • 保存機(jī)器指令的區(qū)域,這個(gè)區(qū)域就是我們所說的代碼段(Code Segment),因此我們可以使用一個(gè)寄存器來專門指向代碼段,這就是CS寄存器的作用,CS也是Code Segment的縮寫。

  • 同樣的道理,程序運(yùn)行起來后還有專門的區(qū)域用來保存數(shù)據(jù),因此必須要專門的寄存器指向數(shù)據(jù)段(Data Segment),這就是DS寄存器的作用,DS是Data Segment的縮寫。

  • 程序運(yùn)行起來后還有運(yùn)行時(shí)棧(Stack Segment),因此可以使用SS寄存器來指向程序員運(yùn)行時(shí)棧,SS是Stack Segment的縮寫。

  • 此外還有ES寄存器,Extra Segment,其用作臨時(shí)段寄存器。

除了內(nèi)存分段管理之外,我們的程序可以讀寫任意內(nèi)存區(qū)域,有的同學(xué)可能不以為意,這又能怎樣呢?

沒有內(nèi)存保護(hù)會(huì)怎樣?

至今,在多線程編程中這個(gè)問題依然困擾著程序員,因?yàn)橥粋€(gè)進(jìn)程中的線程共享同一個(gè)地址空間,這也就意味著你的線程可以修改地址空間中任何可寫的區(qū)域,包括棧區(qū)以及堆區(qū),當(dāng)然這也就意味著其它線程可以修改你的線程使用的數(shù)據(jù),這是多線程中一大類bug的來源,而這個(gè)問題在內(nèi)存地址沒有任何保護(hù)情況下更加嚴(yán)重,因?yàn)檫@時(shí)不是一個(gè)進(jìn)程而是多有進(jìn)程包括操作系統(tǒng)都共享同一個(gè)物理內(nèi)存地址,任何一個(gè)進(jìn)程都可以修改內(nèi)存中任何位置,你的進(jìn)程可以破壞其他進(jìn)程使用的內(nèi)存,可以破壞操作系統(tǒng)使用的內(nèi)存,破壞其它進(jìn)程大不了重新啟動(dòng)這個(gè)進(jìn)程,但是如果破壞了操作系統(tǒng)那么沒有辦法,此時(shí)你只能重新啟動(dòng)計(jì)算機(jī),如果CPU沒有提供內(nèi)存保護(hù)機(jī)制,那么操作系統(tǒng)連自己都保護(hù)不了更何況去保護(hù)其它進(jìn)程。沒想到吧,看似簡(jiǎn)單直接的內(nèi)存讀寫竟然會(huì)有這么多問題。

實(shí)模式

好啦,到目前為止讓我們暫且總結(jié)一下。

  • 絕對(duì)的內(nèi)存地址不好用,這樣的地址必須將程序加載到內(nèi)存的特定位置上,為解決這個(gè)問題使用相對(duì)地址,x86中為每個(gè)程序的區(qū)域都配備有專用的寄存器用來存放該段在內(nèi)存中的起始地址,這樣就可以根據(jù)基址加偏移計(jì)算出物理內(nèi)存地址,注意,這里計(jì)算出來的是真實(shí)的物理內(nèi)存地址。

  • 內(nèi)存讀寫沒有任何保護(hù),程序可以讀寫內(nèi)存的任何區(qū)域。

實(shí)際上這就是早前內(nèi)存管理的模式,非常直接非常原始,x86 CPU將這種原始的內(nèi)存管理方法稱之為實(shí)模式,real mode,這種模式也被稱之為 real address mode,顧名思義,我們?cè)诔绦蛑锌吹降亩际钦鎸?shí)的物理內(nèi)存地址。

原來,早期的x86 CPU能訪問的最大內(nèi)存被限制在1MB(2^20 byte),你可能會(huì)想這可用內(nèi)存也太少了吧,對(duì)于當(dāng)今程序員或者用戶來說1MB幾乎什么都干不了,哪怕都存不下一首歌,然而在上世紀(jì)80年代,1MB內(nèi)存是一片極為廣闊的空間,以至于比爾蓋茨在上世紀(jì)80年代說過:640k ought to be enough for anyone,對(duì)大部分人來說640K內(nèi)存已經(jīng)足夠用了。

除此之外,更加捉襟見肘的是早期x86 CPU寄存器只有16位,16位寄存器是沒有辦法訪問整個(gè)1MB內(nèi)存的,16位寄存器最多能訪問64K大小的內(nèi)存,要想訪問1MB內(nèi)存那么內(nèi)存地址就需要20位,而寄存器本身就16位,因此根本裝不下,怎么辦呢?很簡(jiǎn)單,一個(gè)寄存器不夠我們就用兩個(gè),第一個(gè)寄存器被叫做selector,說白了其實(shí)存放的是儲(chǔ)物柜區(qū)域的編號(hào),因此也叫做段寄存器, segment register,管叫做區(qū)域還是叫做段本質(zhì)上沒啥區(qū)別。第二個(gè)寄存器被叫做offset,說白了就是區(qū)域內(nèi)的編號(hào)或者叫做區(qū)域內(nèi)的偏移,這樣真正的內(nèi)存地址就由兩部分組成 selector:offset,此時(shí)內(nèi)存地址的計(jì)算方式是這樣的:

16 ? selector + offset

此時(shí)給定一個(gè)段寄存器再給出一個(gè)偏移我們就能直接在內(nèi)存中找到需要的數(shù)據(jù):

因此這里計(jì)算出來的內(nèi)存地址就是物理內(nèi)存地址。此外,在實(shí)模式下CPU不提供內(nèi)存保護(hù)機(jī)制,程序可以隨意讀寫任何內(nèi)存區(qū)域,哪怕是操作系統(tǒng)所在的區(qū)域其它程序也可以讀寫?,F(xiàn)在可以總結(jié)下早期x86處理器的特點(diǎn)了:

  • 尋址空間有限,只有1MB

  • 利用 selector:offset的方式利用兩個(gè)16位寄存器來尋址1MB內(nèi)存

  • 沒有內(nèi)存保護(hù)機(jī)制,當(dāng)然,沒有內(nèi)存保護(hù)機(jī)制的一大優(yōu)點(diǎn)就在于內(nèi)存讀寫速度要更快,原因就在于不需要經(jīng)過虛擬內(nèi)存地址到物理內(nèi)存地址的轉(zhuǎn)換,也不需要進(jìn)行任何檢查(這可能是實(shí)模式下僅有的優(yōu)點(diǎn))

在80286之前,所有x86 CPU都運(yùn)行在實(shí)模式下,而為了后向兼容,即使是現(xiàn)代x86在重置(加電時(shí))后也會(huì)首先進(jìn)入實(shí)模式,后續(xù)才會(huì)跳轉(zhuǎn)到保護(hù)模式(protected mode),關(guān)于保護(hù)模式我們?cè)诤罄m(xù)文章中講解。

實(shí)模式與操作系統(tǒng)

實(shí)模式是x86系列處理器最早期的內(nèi)存管理模式,這一時(shí)期的操作系統(tǒng)別無選擇,只能運(yùn)行在這種模式下,早期的DOS系統(tǒng)以及早期的Microsoft Windows操作系統(tǒng)就運(yùn)行在實(shí)模式下。雖然實(shí)模式理解起來很簡(jiǎn)單,但這種模式最主要的問題在于:

  1. 把物理內(nèi)存暴露給程序

  2. 沒有內(nèi)存保護(hù)機(jī)制

這兩者結(jié)合起來的后果就是程序不被受限,程序員都知道,我們寫的代碼充滿了bug,在現(xiàn)代操作系統(tǒng)中程序很容易把自己搞掛,而在早期的操作系統(tǒng)中程序就會(huì)很容易的把整個(gè)系統(tǒng)搞掛,為解決這一問題,x86 CPU在80286開始引入保護(hù)模式,后續(xù)文章會(huì)有詳細(xì)講解。盡管現(xiàn)代操作系統(tǒng)(Windows、Linux)等早已不運(yùn)行在實(shí)模式下,然而實(shí)模式卻依然保留了下來,你可能會(huì)想為什么x86 CPU依然需要保留實(shí)模式呢?我們都知道代碼有屎山一說,其實(shí)對(duì)于歷史悠久的x86來說也有類似的問題。CPU這種硬件和軟件一樣也是在不斷演變進(jìn)化的,從16位實(shí)模式演進(jìn)到了32位保護(hù)模式以及現(xiàn)代的64位處理器,但早期程序員圍繞著16位實(shí)模式的x86CPU編寫了很多軟件,當(dāng)CPU發(fā)展到32位保護(hù)模式時(shí)之前的基于16位實(shí)模式編寫的軟件該怎么辦?不支持了嗎?不支持的話只有兩種可能:1) 用戶不再購買不兼容16位軟件的CPU 2) 重寫代碼,以程序員的尿性來說大概率不會(huì)重寫,intel也非常識(shí)時(shí)務(wù),因此在后來的32位乃至現(xiàn)代的64位處理器上依然保留了實(shí)模式,x86系列處理器在重置時(shí)會(huì)首先進(jìn)入實(shí)模式,對(duì)于不使用實(shí)模式的現(xiàn)代操作系統(tǒng)來說簡(jiǎn)單的初始化工作后會(huì)跳轉(zhuǎn)到保護(hù)模式。因此我們可以看到,實(shí)模式就像原始的進(jìn)化基因一樣依然存在,就像動(dòng)物胚胎有腮一樣,只不過該過程一閃而過,實(shí)模式也是在計(jì)算機(jī)啟動(dòng)階段快速閃現(xiàn),這種古老的內(nèi)存管理方式依然留下了自己的烙印。


總結(jié)

實(shí)模式是一種非常古老的內(nèi)存管理方式,在這種方法下程序員直面物理內(nèi)存,且處理器沒有提供內(nèi)存讀寫機(jī)制,程序員可讀寫任何內(nèi)存區(qū)域。實(shí)際上實(shí)模式對(duì)于現(xiàn)代操作系統(tǒng)來幾乎沒什么用處,只不過如果你針對(duì)x86 CPU編寫操作系統(tǒng)那么實(shí)模式是必須要了解的,但對(duì)于其它CPU來說則沒有這樣的歷史包袱,因此有很多操作系統(tǒng)教材開始基于非X86平臺(tái)來講解,這樣能更快速的講解操作系統(tǒng)而不是在一上來就在各種內(nèi)存模式中打轉(zhuǎn)。注意,本文提到的實(shí)模式僅僅針對(duì)x86系列處理器而言,對(duì)于上層應(yīng)用的大部分程序員來說根本就不需要關(guān)心實(shí)模式,然而技術(shù)就和生物一樣也在不斷演變進(jìn)化,了解過去才能更好的理解當(dāng)下以及未來。


原文作者:碼農(nóng)的荒島求生



一文徹底理解操作系統(tǒng):CPU與實(shí)模式的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
共和县| 古丈县| 藁城市| 屯昌县| 休宁县| 绍兴市| 乾安县| 邢台市| 墨竹工卡县| 师宗县| 通江县| 无棣县| 穆棱市| 肃宁县| 宕昌县| 长沙县| 兴城市| 易门县| 崇文区| 桐梓县| 阳谷县| 乌审旗| 昭觉县| 郸城县| 卢龙县| 大丰市| 石家庄市| 都昌县| 赤城县| 扎囊县| 盐城市| 横峰县| 大关县| 兴隆县| 太康县| 临潭县| 额尔古纳市| 临高县| 汝城县| 桓仁| 泰来县|