前面的幾篇文章講到了頁表,以及構成頁表的頁表描述符,分頁機制(paging)是80386引入的,而在其之前的8086和80286,使用的是分段機制(segmentation)。一些新的處理器架構,比如ARM,從誕生之日,就只支持分頁機制。雖然分段機制看起來似乎是一個上古時代的,已經被淘汰的東西,但畢竟人家是分頁機制的前輩。以兼容性著稱的x86處理器,即便到了今天的64位時代,依然保留了對segmentation的向前兼容,而linux操作系統最開始也是基於i386寫的,所以也保留了對segmentation的支持。了解下歷史,往往可以讓我們對後來出現的某些事物有更好的理解。
提到segment,做嵌入式軟體的同學可能會想到elf(executable and linkable file)文件,一個elf文件包含了text段,data段,bss段。Linux操作系統在載入elf文件運行進程後,還會生成stack段, heap段,每個segment用一個vm_area_struct結構體管理。x86中segment劃分也是類似的,包括cs(code segment),ds(data segment),ss(stack segment)等。同elf和linux中軟體實現的segment有所不同,x86中的segmentation機制含有更多硬體的參與,比如硬體實現的對許可權位的檢測(類似於MMU對頁表描述符中許可權位的檢測)。此外,x86中還有一些特殊的system segment,比如存儲task相關信息,以提供對context switch的硬體支持的task state segment。
讓我們從1978年的8086開始,看看x86中的segmentation機制到底是怎樣一回事。
8086實模式時代
8086的CPU是16位的,但intel的工程師希望在不改變CPU寄存器和指令集的基礎上,讓它可以可以定址更大的內存範圍。於是他們使用了一種叫segmentation的機制,即一個邏輯地址(logical address)由segment加上offset組成,一般表達為segement:offset的形式。