在簡單模型中,儲存器系統是乙個線性的位元組陣列,而cpu能夠在乙個常數時間內訪問每個儲存器位置。實際上,儲存器系統(memory system)是乙個具有不同容量、成本和訪問時間的儲存器層次結構。cpu暫存器儲存著最常用的資料。靠近cpu的小的、快速的高速緩衝儲存器(cache memory)作為一部分儲存在相對慢速的主儲存器(main memory)中的資料和指令的緩衝區域。主存暫時存放儲存在容量較大、慢速磁碟上的資料,而這些磁碟又常常作為儲存在通過網路連線的其它機器的磁碟上的資料的緩衝地帶。
如果程式所需的資料儲存在cpu暫存器中,那麼在指令的執行期間,在0個週期內就能訪問到它們。如果在高速緩衝儲存器內,需要1~30個週期。如果儲存在主存中,需要50~200個週期。而如果在磁碟上,則需要大約幾千萬個週期。
3.儲存器層次結構圍繞著電腦程式的乙個稱為區域性性(locality)的基本屬性。具有良好區域性性的程式傾向於一次又一次的訪問相同的資料項集合,或是傾向於訪問鄰近的資料項集合。區域性性通常有兩種不同的形式:時間區域性性(temporal locality)和空間區域性性(spatial locality)。
由於歷史原因,雖然rom中有的型別既可以讀又可以寫,但是整體上還是叫做唯讀訪問器(read-only memory,rom),儲存在rom中的 程式常常被稱為韌體(firmware)。
理解儲存器層次結構本質的程式設計師能夠利用這些知識編寫出更有效的程式,無論具體的儲存器系統是怎樣實現的。特別地,我們推薦以下技術:1)將注意力集中在內迴圈上,大部分計算和儲存器訪問都發生在這裡。2)通過按照資料物件儲存在儲存器中的順序、以步長為1來讀取資料,從而使程式的空間區域性性最大。3)一旦程式中讀入了乙個資料物件,就盡可能多的使用它,從而使程式中的時間區域性性最大。
引言:現代作業系統與硬體合作,為每個程式提供一種幻象,好像這個程式是在獨佔的使用處理器和主存,而實際上,在任何時刻,系統上都有多個程式在執行。
鏈結(linking)是將各種**和資料部分收集起來並組合成乙個單一檔案的過程(感覺該句描述欠妥,應該是針對目標檔案而非**檔案),這個檔案可以被載入(或被拷貝)到儲存器執行。鏈結可以執行於編譯時(compile time),也就是在源**被翻譯為機器**時;也可以執行於載入時(load time),也就是程式被載入器(loader)載入到儲存器並執行時;甚至執行與執行時(run time),由應用程式執行。
鏈結器對目標機器知之甚少,產生目標檔案的編譯器和彙編器已經完成了大部分工作了。
當編譯器遇到乙個不是在當前模組中被定義的符號(變數或函式名)時,它就會假設該符號是在其它某個模組中被定義的,生成乙個鏈結器符號表條目,並把它交給鏈結器處理。如果鏈結器在它的任何輸入模組中都找不到這個被引用的符號,它就輸出一條錯誤資訊並終止。
共享庫(shared library)是致力於解決靜態庫缺陷的乙個現代創新產物。共享庫是乙個目標模組,在執行時,可以載入到任意的 儲存器位址,並和乙個在儲存器中的程式鏈結起來。這個過程稱為動態鏈結(dynamic linking),是由乙個叫做動態鏈結器(dynamic linker)的程式執行的。
每個unix程式都有乙個執行時儲存器映像,在32位linux系統中,**段總是從位址0x08048000處開始。資料段是在接下來的乙個4kb對齊的位址處。執行時堆在讀/寫段之後接下來的第乙個4kb對齊的位址處,並通過呼叫malloc庫向上增長。使用者棧總是從最大的合法使用者位址開始,向下增長的(向低儲存器位址方向增長)。從棧的上部開始的段是為作業系統駐留儲存器部分(也就是核心)的**和資料保留的。
現代作業系統通過使控制流發生突變對系統狀態的變化做出響應。一般而言,我們把這些突變稱為異常控制流(exceptional control flow,ecf)。異常控制流發生在計算機系統的各個層次。比如,在硬體層,硬體檢測到的事件會觸發控制突然轉移到異常處理程式。在作業系統層,核心通過上下文轉換將控制從乙個使用者程序轉移到另乙個使用者程序。在應用層,乙個程序可以傳送訊號到另乙個程序,而接收者會將控制突然轉移到它的乙個訊號處理程式。乙個程式可以通過迴避通常的棧規則,並執行到其他函式中任意位置的非本地跳轉來對錯誤做出反應。
異常(exception)是異常控制流的一種形式,它一部分是由硬體實現的,一部分是由作業系統實現的。異常就是控制流中的突變,用來響應處理器狀態中的某些變化。
在任何情況下,當處理器檢測到有事件發生時,它就會通過一張叫做異常表(exception table)的跳轉表(即16位下的中斷向量表和32位下的中斷描述符表),進行乙個間接過程呼叫(異常),到乙個專門設計用來處理這類事件的作業系統子程式(異常處理程式(exception handler))。
系統中把每種可能發生的異常都分配了乙個唯一的非負整數的異常號(exception number)。異常號是到異常表的索引,異常表的起始位址放在乙個叫做異常表基址暫存器(exception table base register)的特殊cpu暫存器裡。(x86叫中斷描述符表暫存器idt(interrupt descriptor table))。
異常可以分為四類:中斷(interrupt)、陷阱(trap)、故障(fault)和終止(abort)。
6.中斷是非同步產生的,是來自處理器外部的i/o裝置的訊號的結果。硬體中斷不是由任何一條專門的指令造成的,從這個意義上來說它是非同步的。硬體中斷的異常處理程式通常稱為中斷處理程式(interrupt handler)。i/o裝置,例如網路介面卡、磁碟控制器和定時器晶元,通過向處理器晶元上的乙個引腳發訊號,並將異常號放到系統匯流排上,以觸發中斷,這個異常號標識了引起中斷的裝置。
陷阱是有意的異常,實質性一條指令的結果。就像中斷處理程式一樣,陷阱處理程式將控制返回到下一條指令。陷阱最重要的用途就是在使用者程式和核心之間提供乙個像過程一樣的介面,叫做系統呼叫。
故障是由錯誤引起的,它可能被故障處理程式修正。當故障發生時,處理器將控制轉移到故障處理程式。如果處理程式能夠修正這個錯誤情況,它就會將控制返回到引起故障的指令,從而重新執行它。否則,處理程式返回到核心的abort例程,abort例程會終止引起故障的應用程式。
終止是不可恢復的致命錯誤造成的結果,通常是一些硬體錯誤,例如dram或者sram位被損壞時發生的奇偶錯誤。終止處理程式從不將控制返回給應用程式。
為了使描述更具體,讓我們來看看為ia32系統定義的一些異常。有高達256種不同的異常型別。0~31的號碼是由intel架構師定義的異常,因此對任何ia32的系統都是一樣的。32~255的號碼對應的是作業系統中定義的中斷和陷阱。
每個linux系統呼叫都有乙個唯一的整數號(系統呼叫號),對應於乙個到核心中跳轉表的偏移量。歷史上系統呼叫是通過異常128(0x80)提供的。
c程式用syscall函式可以直接呼叫任何系統呼叫。然而,實際中幾乎沒有必要這麼做。對於大多數系統呼叫,標準c庫提供了一組方便的包裝函式。這些包裝函式將引數打包到一起,以適當的系統呼叫號陷入核心,然後將系統呼叫的返回狀態傳遞給呼叫程式。
所有的linux系統呼叫的引數都是通過暫存器而不是棧來傳遞資料的。按照慣例,%eax暫存器儲存系統呼叫號,暫存器%ebx、%ecx、%edx、%esi、%edi和%ebp最多包含任意6個引數。棧指標%esp不能使用,因為當進入核心,模式時,核心會覆蓋它。
程序是電腦科學中最深刻最成功的概念之一。程序的經典定義就是乙個執行中的程式的例項。系統中的每個程式都是執行在某個程序的上下文(context)中的。上下文是由程式正常執行所需的狀態組成的。這個狀態包括存放在儲存器中的程式**和資料,它的棧、通用目的暫存器的內容、程式計數器、環境變數以及開啟的檔案描述符的集合。
核心為每個程式維持乙個程序上下文。上下文就是核心重新啟動乙個被搶占的程序所需要的狀態。它由一些物件的值組成,這些物件包括通用的目的暫存器、浮點暫存器、程式計數器、使用者棧、狀態暫存器、核心棧和各種核心資料結構,比如描繪位址空間的頁表、包含有關當前程序資訊的程序表,以及包含程序已開啟檔案的資訊的檔案表。
《深入理解計算機系統》讀書筆記
小端模式 低有效位元組在前,高有效位元組在後 代表處理器 intel 大端模式 高有效位元組在前,低有效位元組在後 代表處理器 ibm power sun c語言允許無符號整數與有符號整數之間的轉換,轉換規則是 底層的位保持不變 當執行乙個運算時,若兩個數乙個為無符號數,乙個是有符號數,則c語言隱式...
《深入理解計算機系統》讀書筆記
ip位址是乙個32為無符號整數,ip位址存放在ip位址結構體中 struct in addr tcp ip規定統一的網路位元組順序 大端位元組順序 因為主機位元組順序 host byte order 是小端法,所以必須有函式用於轉換。htonl函式和ntohl是32位整數,short是16位整數 i...
深入理解計算機系統(讀書筆記)
計算機的資訊儲存和處理都是以二進位制為基礎的,通過一系列的0,1組合,我們能夠去表示有限的整數和實數。首先了解三種重要的符號表示方法 有符號表示 用於表示大於或等於0的整數 無符號表示 用於表示有正有負的整數 浮點數 以科學計數法為基礎的二進位制表示方法 在計算機內部資料是按照字進行儲存的,字有著統...