首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

x86 保護模式控制轉移深度解析:任務內特權級轉換與任務切換(上)

     編輯:組合語言

在 x86 保護模式下,控制轉移是系統程式設計的核心。本文系統闡述同一任務內的控制轉移,重點剖析段間轉移的特權級檢查機制,為理解呼叫門、中斷門、任務切換奠定基礎。

控制轉移分類

  • 任務內轉移: 段內轉移(JMP/CALL/RET 近轉移)、同特權級段間轉移、跨特權級段間轉移。
  • 任務間轉移: 任務切換(透過 TSS、任務門)。

段內轉移不涉及特權級變更,類似實模式。所有特權級檢查與保護機制,均發生在段間轉移中。

段間轉移指令與目標地址指標

具備段間轉移功能的指令:JMP FAR、CALL FAR、RET FAR、INT n、IRET、異常/中斷處理。

  • 16 位代碼段: 目標指標 = 16 位選擇子 + 16 位偏移(32 位指標)。
  • 32 位代碼段: 目標指標 = 16 位選擇子 + 32 位偏移(48 位全指標)。

直接 vs 間接轉移

  • 直接轉移: 指令中直接包含目標代碼段選擇子與偏移。選擇子指向代碼段描述符。
  • 間接轉移: 指令中選擇子指向門描述符(呼叫門、中斷門、陷阱門、任務門)或 TSS 描述符。偏移部分被忽略。

處理器執行段間轉移的核心步驟

  1. 檢查選擇子非空(索引 ≠ 0,即非 GDT 第 0 項空描述符)。
  2. 根據選擇子 TI 位,從 GDT 或 LDT 讀取描述符。
  3. 驗證描述符類型正確性(必須為代碼段或門類型),調整 RPL。
  4. 將目標代碼段描述符資訊載入 CS 隱藏快取暫存器(段基址、界限、屬性、DPL)。
  5. 檢查偏移是否超出代碼段界限。
  6. 載入 CS(選擇子)與 EIP;CPL 更新為選擇子 RPL 欄位值。

載入 CS 快取時的保護檢查(核心邏輯)

設目標代碼段描述符 DPL = 目標特權級,當前 CPL = 當前特權級,選擇子 RPL = 請求特權級。

非一致代碼段

  • CPL = DPL(只能同級轉移)
  • RPL ≤ DPL(請求特權級不得高於目標)

違反任一條件 → #GP(選擇子)。

一致代碼段

  • CPL ≥ DPL(當前特權級數值不小於目標,即權限不高於目標)
  • RPL 不檢查(隱含滿足)

一致代碼段允許低特權程式呼叫高特權庫常式,不改變 CPL,在呼叫者特權級下執行,實現共享庫機制。

通用檢查

  • 段必須存在(P=1),否則 #NP(選擇子)。
  • 描述符類型必須為代碼段。

任務內無特權級變換的轉移實現

指 CPL 保持不變的段間轉移。

1. 直接 JMP / CALL

  • 目標為代碼段描述符。
  • 滿足上述非一致段 CPL=DPL、RPL≤DPL 或一致段 CPL≥DPL。
  • CALL 會壓入返回指標(CS:EIP),JMP 不壓棧。
  • 無法跨特權級(CPL 不變)。

2. 直接 RET FAR

  • 從棧彈出目標指標,選擇子指向代碼段。
  • 需滿足 RPL = CPL(返回目標必須同級)。
  • 配對同級 CALL 使用。

3. 透過門機制

呼叫門、中斷門等可實現同級轉移,詳細留待後續文章。

載入資料段/堆疊段暫存器的特權檢查

指令:MOV Sreg, selector、POP Sreg、LDS/LES/LFS/LGS/LSS、任務切換時自動載入。

資料段暫存器 (DS, ES, FS, GS)

  • 選擇子非空。
  • 描述符類型:資料段、可讀代碼段、一致可讀代碼段。
  • CPL ≤ DPL 且 RPL ≤ DPL(數據段/可讀代碼段)。
  • 段存在(P=1)。

堆疊段暫存器 (SS)

  • 選擇子非空。
  • 描述符類型:可讀寫資料段(必須可寫)。
  • CPL = DPL = RPL(三者完全相等,嚴格同級)。
  • 段存在(P=1)。

違反即觸發 #GP 或 #SS 異常。


範例三:任務內同級轉移演示(含 LDT 使用)

本範例展示完整流程:實模式初始化 GDT/LDT → 進入保護模式 (CPL=0) → 載入 LDTR、建立堆疊 → 同級段間 JMP (K→L) → 同級 CALL 子程序 (L→C 顯示/轉換) → 同級 JMP 返回 (L→K) → 回實模式。

關鍵結構設計

  • GDT: 空描述符、Normal 段、代碼段 K、LDT 描述符。
  • LDT (任務私有): 代碼段 L、代碼段 C、顯示緩衝區段、LDT 別名段 (DPL=3)、訊息資料段 (DPL=3)、堆疊段。
  • 選擇子計算:CodeL_Sel = CodeL - LDT + TIL (TI=1) 等。

LDT 基址初始化細節

LDT 位於獨立段,其描述符基址需在實模式下計算並填入 GDT 的 LDT 描述符。範例提供 Init_MLDT 程序,將 LDT 內所有描述符的基址從段相對轉為線性位址(段值×16+偏移)。

返回實模式前的段快取修復

代碼段 K 結束前,將 Normal_Sel 載入 ES/FS/GS/SS,確保這些段快取的界限=0xFFFF、屬性符合實模式預期。不能從 32 位代碼段直接返回實模式,因 32 位代碼段描述符 D=1,實模式無法修改段屬性,會導致後續實模式代碼執行錯誤。

總結

保護模式控制轉移的核心在於描述符類型檢查與特權級比較規則。同級轉移相對簡單,但跨特權級轉移(呼叫門、中斷門、任務門)才是作業系統實現系統呼叫、中斷處理、多任務的關鍵,將在下篇詳細剖析。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved