2008年2月5日 星期二

IA-32 Architecture (1/4)

簡介

若要撰寫 assembly,就必須要了解處理器的架構,目前最常見的事 IA(Intel Architecture)-32 架構,市面上的 Pentium、Celeron、Xeon .... 等等 CPU 都是屬於 IA-32 架構,並支援兩種不同的記憶體架構,分別為 real mode 與 protected mode。

關於 80x86 處理器的演化過程以及每個階段所加入的改變,可以參考 小木偶的網頁 - 組合語言準備工作 一文得到詳細的說明。


Processor Execution Cycle

CPU 的執行週期大概可以分為三個階段:
  1. Fetch:從記憶體中取得指令
    放置正確的位址到 address bus 上,並在 control bus 上輸入 memory read 訊號讓指令可以在正確的記憶體中被取出。
  2. Decode:將指令解碼
    此階段必須辨識從記憶體中取出的指令為何,並進行解碼的動作,這裡有相對應的 schema 可以將其轉為 machine language。
  3. Execute:執行指令
    執行指令時,CPU 中的控制電路會負責時間的控制,而 ALU(Arithmetic & Logic Unit) 則會負責針對資料進行數學及邏輯相關運算處理。

這三個階段通常被稱為 fetch-decode-execute cycle(或是 execution cycle),以下用一張簡單的圖來說明:

其實 Execution Cycle 通常不是在主記憶體中完成,而是在 cache 中,因為 cache 的速度比記憶體更快,不過由於這一段(CPU <-> cache <-> memory)是透明的,因此撰寫應用程式時不需要考量到這個。


Process Registers

在 IA-32 架構中,提供了 10 個 32-bit 以及 6 個 16-bit 的 register,根據用途不同可分為 generalcontrolsegment .... 等幾種;其中 general 還細分為 datapointerindex 三種 register。

以下針對不同的 register 進行說明:

Data Registers

首先先用一張圖說明 data register 的組成:


這 4 個 32-bit 的 data register 可以用在數學、邏輯、或是其他不同的處理。且看其結構,可以知道為了與上一代的 CPU 相容的設計:
  1. 4 個 32-bit register:EAX、EBX、ECX、EDX
  2. 8 個 16-bit register:AX、BX、CX、DX
  3. 8 個 8-bit register:AH、AL、BH、BL、CH、CL、DH、DL

每一個 register 都是獨立的,因此可以根據需求決定使用 8-bit、16-bit、或是 32-bit 的 register。

但存取時就必須注意一下,假設要讀取 EAX 中的 lower 16 bits 的資料,可以直接存取 AX,會得到相同的效果(因為 AX 本來就是 EAX lower 16 bit 的部分);若是要存取 AX 中 higher 8 bit 的資料,則可以直接存取 AH(因為 AH 為 AX 的 higher 8 bit)。

一般來說,這幾個 register 進行任何數學、邏輯處理都不會有問題,但還是有特例,例如:進行乘法時必須用到 EAX(或是 AX、或是 AL) register;進行迴圈處理時,ECX(或 CX) 則是儲存迴圈執行次數的 register;這些特例都是必須要注意的。

Pointer & Index Registers

首先用一張圖說明 pointer & index register 的組成:


首先,這兩種 register 與 data register 類似,也是 32-bit 與 16-bit 的組合,使用上就端看所處理的資料長度來進行不同的運用。

index register 通常用於字串處理的指令上,除此之外,可以當作一般的 data register 使用。

pointer register 則是專門負責管理 stack 狀態(其實也可以將其當作 data register 使用,不過還是多用於 stack 上)。

Control Registers

control register 有兩個,分別是 flags register 以及 instruction register,以下用一張圖來表示:


instruction pointer register(有時稱為 program counter register) 的作用在於儲存下一個準備被執行的指令所在的記憶體位址之用,當指令從記憶體中被取出後,instruction pointer register 的內容則會更新為下一個準備執行的指令所在的記憶體位址。

另外若是使用傳送 jump、procedure call、interrupt 等控制訊號,亦會更改 instruction pointer register 的內容。

使用上若是需要 32-bit 長度,可使用 EIP;若是 16-bit 則使用 IP。

flags register 也是相同,包含 32-bit 及 16-bit;以 EFLAGS(32-bit) 來說,包含了 6 個 status flag、1 個 control flag、10 個 system flag(詳細名稱可以參考上圖),而 EFLAGS 中的每個 bit 都是獨立有其意義的,可以是 1(set) 或 0(clear),可以用指令修改,例如:clc 指令可設定 carry flag 為 0,stc 指令則可設定 carry flag 為 1。

但 flag register 通常是用來記錄運算、邏輯處理的狀態之用,以下舉幾個例子來說明:
  1. 進行減法時結果為 0,ZF(zero flag) 會設定為 1
  2. 處理字串時,可以使用 DF(direction flag) 來決定掃瞄字串的方向(forward or backward)
  3. 將 TF(trap falg) 設定為 1,可以讓 CPU 以一行一行的方式執行程式,對於 debug 會有相當幫助
  4. ID(identification flag) 則是用來決定是否支援 CPUID 這個指令

Segment Registers

最後 6 個 16-bit register 就是 segment register,以下用一張圖來說明 segment register 的組成:


在 IA-32 架構下,記憶體會被分為數個 segment,每個 segment 是一小部分的記憶體空間,而 segment register 中儲存的則是指向這些記憶體空間的位址。

但由於只有 6 個 segment register,因此 CPU 最多同一時間僅能存取六個不同的 memory segment。

另外,程式在邏輯上分為兩個部分,分別是 codedata;其中 code 的部分所存的僅有指令,而 data 的部分則是僅有程式所需要的資料。

而 CS(code segment) 中所儲存的正是 code 所在的記憶體位址,而 DS(data segment) 儲存的則是 data 所在的記憶體位址,另外,SS(stack segment) 中儲存的則是指向程式的 stack segment 的記憶體位址。

另外三個 ES、FS、GS,則是額外的 segment register,可以作為類似其他的 segment register 使用,例如:當一個 DS 不足以儲存程式所使用資料的記憶體位址,則可能會借用這三個額外 segment register 來使用。

沒有留言:

張貼留言