寄存器這個太多太復雜,不適合寫故事,拖了很久,總算是寫完了,這篇文章就來詳細聊聊x86/x64架構的CPU中那些紛繁復雜的寄存器們。
長文預警,時速較快,請系好安全帶~起飛~
自1946年馮·諾伊曼領導下誕生的世界上第一臺通用電子計算機ENIAC至今,計算機技術已經發(fā)展了七十多載。
從當初專用于數學計算的龐然大物,到后來大型機服務器時代,從個人微機技術蓬勃發(fā)展,到互聯網浪潮席卷全球,再到移動互聯網、云計算日新月異的當下,計算機變的形態(tài)各異,無處不在。
這七十多年中,出現了數不清的編程語言,通過這些編程語言,又開發(fā)了無數的應用程序。
可無論什么樣的應用程序,什么樣的編程語言,最終的程序邏輯都是要交付給CPU去執(zhí)行實現的(當然這里有些不嚴謹,除了CPU,還有協處理器、GPU等等)。所以了解和學習CPU的原理都是對計算機基礎知識的夯實大有裨益。
在七十多年的漫長歷程中,也涌現了不少架構的CPU。
- MIPS
- PowerPC
- x86/x64
- IA64
- ARM
- ······
這篇文章就以市場應用最為廣泛的x86-x64架構為目標,通過學習了解它內部的100個寄存器功能作用,來串聯闡述CPU底層工作原理。
通過這篇文章,你將了解到:
- CPU指令執(zhí)行原理
- 內存尋址技術
- 軟件調試技術原理
- 中斷與異常處理
- 系統(tǒng)調用
- CPU多任務技術
什么是寄存器?
寄存器是CPU內部用來存放數據的一些小型存儲區(qū)域,用來暫時存放參與運算的數據和運算結果以及一些CPU運行需要的信息。
x86架構CPU走的是復雜指令集(CISC) 路線,提供了豐富的指令來實現強大的功能,與此同時也提供了大量寄存器來輔助功能實現。這篇文章將覆蓋下面這些寄存器:
- 通用寄存器
- 標志寄存器
- 指令寄存器
- 段寄存器
- 控制寄存器
- 調試寄存器
- 描述符寄存器
- 任務寄存器
- MSR寄存器
通用寄存器
首當其沖的是通用寄存器,這些的寄存器是程序執(zhí)行代碼最最常用,也最最基礎的寄存器,程序執(zhí)行過程中,絕大部分時間都是在操作這些寄存器來實現指令功能。
所謂通用,即這些寄存器CPU沒有特殊的用途,交給應用程序“隨意”使用。注意,這個隨意,我打了引號,對于有些寄存器,CPU有一些潛規(guī)則,用的時候要注意。
在x64架構中,上面的通用寄存器都擴展成為64位版本,名字也進行了升級。當然,為了兼容32位模式程序,使用上面的名字仍然是可以訪問的,相當于訪問64位寄存器的低32位。
rax rbx rcx rdx rsp rbp rsi rdi
除了擴展原來存在的通用寄存器,x64架構還引入了8個新的通用寄存器:
r8-r15
在原來32位時代,函數調用時,那個時候通用寄存器少,參數絕大多數時候是通過線程的棧來進行傳遞(當然也有使用寄存器傳遞的,比如著名的C++ this指針使用ecx寄存器傳遞,不過能用的寄存器畢竟不多)。
進入x64時代,寄存器資源富裕了,參數傳遞絕大多數都是用寄存器來傳了。寄存器傳參的好處是速度快,減少了對內存的讀寫次數。
當然,具體使用棧還是用寄存器傳參數,這個不是編程語言決定的,而是編譯器在編譯生成CPU指令時決定的,如果編譯器非要在x64架構CPU上使用線程棧來傳參那也不是不行,這個對高級語言是無感知的。
標志寄存器
標志寄存器,里面有眾多標記位,記錄了CPU執(zhí)行指令過程中的一系列狀態(tài),這些標志大都由CPU自動設置和修改:
- CF 進位標志
- PF 奇偶標志
- ZF 零標志
- SF 符號標志
- OF 補碼溢出標志
- TF 跟蹤標志
- IF 中斷標志 ······
在x64架構下,原來的eflags寄存器升級為64位的rflags,不過其高32位并沒有新增什么功能,保留為將來使用。
指令寄存器
eip : 指令寄存器可以說是CPU中最最重要的寄存器了,它指向了下一條要執(zhí)行的指令所存放的地址,CPU的工作其實就是不斷取出它指向的指令,然后執(zhí)行這條指令,同時指令寄存器繼續(xù)指向下面一條指令,如此不斷重復,這就是CPU工作的基本日常。
而在漏洞攻擊中,黑客想盡辦法費盡心機都想要修改指令寄存器的地址,從而能夠執(zhí)行惡意代碼。
同樣的,在x64架構下,32位的eip升級為64位的rip寄存器。
段寄存器
段寄存器與CPU的內存尋址技術緊密相關。
早在16位的8086CPU時代,內存資源寶貴,CPU使用分段式內存尋址技術:
16位的寄存器能尋址的范圍是64KB,通過引入段的概念,將內存空間劃分為不同的區(qū)域:分段,通過段基址+段內偏移段方式來尋址。
這樣一來,段的基地址保存在哪里呢?8086CPU專門設置了幾個段寄存器用來保存段的基地址,這就是段寄存器段的由來。
段寄存器也是16位的。
段寄存器有下面6個,前面4個是早期16位模式就引入了,到了32位時代,又新增了fs和gs兩個段寄存器。
- cs : 代碼段
- ds : 數據段
- ss : 棧段
- es : 擴展段
- fs : 數據段
- gs : 數據段
段寄存器里面存儲的內容與CPU當前工作的內存尋址模式緊密相關。
當CPU處于16位實地址模式下時,段寄存器存儲段的基地址,尋址時,將段寄存器內容左移4位(乘以16)得到段基地址+段內偏移得到最終的地址。
當CPU工作于保護模式下,段寄存器存儲的內容不再是段基址了,此時的段寄存器中存放的是 段選擇子 ,用來指示當前這個段寄存器“指向”的是哪個分段。
注意我這里的指向打了引號,段寄存器中存儲的并不是內存段的直接地址,而是段選擇子,它的結構如下:
16個bit長度的段寄存器內容劃分了三個字段:
這里提到了兩個表,全局描述符表GDT和局部描述符表LDT,關于這兩個表的介紹,下面介紹描述符寄存器時再詳述,這里只需要知道,這是CPU支持分段式內存管理需要的表格,放在內存中,表格中的每一項都是一個描述符,記錄了一個內存分段的信息。
保護模式下的段寄存器和段描述符到最后的內存分段,通過下圖的方式聯系在一起:
通用寄存器、段寄存器、標志寄存器、指令寄存器,這四組寄存器共同構成了一個基本的指令執(zhí)行環(huán)境,一個線程的上下文也基本上就是這些寄存器,在執(zhí)行線程切換的時候,就是修改它們的內容。
控制寄存器
控制寄存器是CPU中一組相當重要的寄存器,我們知道eflags寄存器記錄了當前運行線程的一系列關鍵信息。
那CPU運行過程中自身的一些關鍵信息保存在哪里呢?答案是控制寄存器!
32位CPU總共有cr0-cr4共5個控制寄存器,64位增加了cr8。他們各自有不同的功能,但都存儲了CPU工作時的重要信息:
- cr0 : 存儲了CPU控制標記和工作狀態(tài)
- cr1 : 保留未使用
- cr2 : 頁錯誤出現時保存導致出錯的地址
- cr3 : 存儲了當前進程的虛擬地址空間的重要信息——頁目錄地址
- cr4 : 也存儲了CPU工作相關以及當前人任務的一些信息
- cr8 : 64位新增擴展使用 其中,CR0尤其重要,它包含了太多重要的CPU信息。
一些重要的標記位含義如下:
PG
: 是否啟用內存分頁
AM
: 是否啟用內存對齊自動檢查
WP
: 是否開啟內存寫保護,若開啟,對只讀頁面嘗試寫入時將觸發(fā)異常,這一機制常常被用來實現寫時復制功能
PE
: 是否開啟保護模式
除了CR0,另一個值得關注的寄存器是CR3,它保存了當前進程所使用的虛擬地址空間的頁目錄地址,可以說是整個虛擬地址翻譯中的頂級指揮棒,在進程空間切換的時候,CR3也將同步切換。
-
寄存器
+關注
關注
31文章
5294瀏覽量
119814 -
cpu
+關注
關注
68文章
10804瀏覽量
210829 -
X86
+關注
關注
5文章
293瀏覽量
43365 -
X64
+關注
關注
0文章
5瀏覽量
7827
發(fā)布評論請先 登錄
相關推薦
評論