亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
樓主: mik
打印 上一主題 下一主題

【x86 & x64 沉思錄】(6.7 更新) [復(fù)制鏈接]

論壇徽章:
0
11 [報告]
發(fā)表于 2009-02-24 02:38 |只看該作者
5.6、 觀察 xp 實際的 segmentation 情景



使用 bochs 可以很容易很直觀地觀察調(diào)試系統(tǒng)。下面選取一個 xp 啟動的實際片斷,如下:

<bochs:7> sreg
cs:s=0x001b, dl=0x0000ffff, dh=0x00cffa00, valid=1
ds:s=0x0023, dl=0x0000ffff, dl=0x00cff300, valid=31
ss:s=0x0023, dl=0x0000ffff, dl=0x00cff300, valid=31
ss:s=0x0023, dl=0x0000ffff, dl=0x00cff300, valid=31
fs:s=0x003b, dl=0xe000ffff, dl=0x7f40f3fd, valid=7
gs:s=0x0000, dl=0x00000000, dl=0x00000000, valid=0
ldtr:s=0x0000, dl=0x00000000, dh=0x00000000, valid=0
tr:s=0x0028, dl=0x200020ab, dh=800008b04, valid=1
gdtr:base=0x8003f000, limit=0x3ff
idtr:base=0x8003f400, limit=0x7ff



1、GDTR.base 是 0x8003f000, GDTR.limit 是 0x3ff
2、IDTR.base 是 0x8003f400, IDTR.limit 是 0x7ff
3、LDTR.selector  為 0x0000

這里沒有建立 LDT,它的 selector 是 0x0000,也就是 NULL descriptor。



5.6.1、  觀察 cs register

觀察 cs 的信息:
1、cs 使用的 selector 正是前面提到的 0x1b
2、接下來的 dl=0x0000ffff, dh=0x00cffa00 其實就是 descriptor 信息。

來看一看 cs 的 descriptor 的什么:

<bochs:8> x/2 0x8003f000+3*8
0x8003f018 <bogus+    0>:  0x0000ffff   0x00cffa00


  cs 使用的 selector 是 0x1b,因此:selector.RPL = 3  使用的權(quán)限 3   selector.TI = 0,使用 GDT,selector.SI = 3

  descriptor 的地址在:gdtr.base + 3 * 8 = 0X8003f018。

  它的值按 64 位顯示是:0x00cffa00_0000ffff。


那么,descriptor 的信息:
1、 base = 0x00000000,這是 32 位值。
2、 limit = 0xffffff,這是一個 20 位的值。
3、 DPL = 11b,也就是 3 級。
4、 S 位是 1,它是一個非系統(tǒng)的 descriptor,也就是屬于 segment descriptor。
5、 type 是 1010b,顯示它是一個 execute/readable  non-conforming 類型的 code segment descriptor。
6、 limit 的粒度位 G 位是 1,顯示它是 4K 粒度的。
7、 最后缺省位 D 位是 1, 表明目標(biāo) code segment 的 32 位代碼。

  對這個 descriptor 描述的信息,歸納一下為:segment 是 32 位的代碼段,基地址是 0x00000000,訪問權(quán)限是 3 級,limit 是 0xFFFFF * 0x1000 + 0xFFF = 4G。
  物理上這個 descriptor 被加載到 cs register 里。




5.6.2、 觀察 ds register

  我們看看 ds 加載的 descriptor 的又是怎樣的。
  ds 使用的 selector 是 0x23:TI = 0,SI = 4 以及 RPL = 3。

獲取 descirptor :
<bochs:9> x/2 0x8003f000+4*8
0x8003f020 <bogus+    0>:  0x0000ffff   0x00cff300


這個 descriptor 的值是:0x00cff300_0000ffff  (64 位值)


1、 base = 0x00000000,這是 32 位值。
2、 limit = 0xffffff,這是一個 20 位的值。
3、 DPL = 11b,也就是 3 級。
4、 S 位是 1,它是一個非系統(tǒng)的 descriptor,也就是屬于 segment descriptor。
5、 type 是 0011b,顯示它是一個具有 R/W 權(quán)限的 data segment descriptor。
6、 limit 的粒度位 G 位是 1,顯示它是 4K 粒度的。
7、 最后缺省位 D 位是 1, 同 code segment descriptor 意義一致

---------------------------

這個 descriptor 與上面 cs 的 descriptor 不同之處僅是 type 不同。這個 descriptor 是個 data segment descriptor。



5.6.3、 平坦的內(nèi)存模式

  現(xiàn)在的操作系統(tǒng)絕大部分使用平坦的內(nèi)存模式,這種模式下,所有 segment 的基址是 0x00000000,但是 windows 使用了 FS 來定義非零基址的段。 FS 描述的段的基地址是:0x7f3de000,使用 FS 來管理一些系統(tǒng)信息。
  使用了平坦模式,導(dǎo)致可以使用 ds 讀取 cs 的數(shù)據(jù),或者可以執(zhí)行 cs 以外的如:ds 或 ss 的代碼。在 segmentation 這個階段里 processor 無法阻止 stack 里的代碼可以執(zhí)行這一情況。直至在 paging 保護措施上才得到解決。

  既然使用了平坦模式,邏輯地址與線性地址是一致的。導(dǎo)致現(xiàn)代操作系統(tǒng)已經(jīng)弱化邏輯地址這個概念,虛擬地址一般就指線性地址

因此:對于兩條指令
  mov eax, dword ptr cs:[0x8012100]
      mov eax, dword ptr ds:[0x8012100]
      -------------------------------------
      結(jié)果是完全一致的。當(dāng)然這是有提前的。提前是:cs 裝的這個 code segment 是可讀的。



但是,對于這兩條指令,情況就不同了:

  mov dword ptr cs:[0x8012100],eax
      mov dword ptr ds:[0x8012100],eax
     -------------------------------------
     第 1 條是會出錯的。這里 cs 裝的 code segment 是不可寫的。

論壇徽章:
0
12 [報告]
發(fā)表于 2009-02-24 15:02 |只看該作者
5.7、 segmentation 下的 protected 核心




segment descriptors 構(gòu)建保護模式下的最基本、最根本的執(zhí)行環(huán)境。system descriptors 則構(gòu)建保護模式下的核心組件:

1、TSS descriptor 提供硬件級的進程切換機制
2、LDT descriptor 供進程使用多個 descriptor
3、Gate descriptor 提供 processor 權(quán)限級別的切換機制。



5.7.1、 TSS 提供的進程切換機制


TSS 是一段內(nèi)存區(qū)域,存放進程相關(guān)的執(zhí)行環(huán)境信息。初始化的 TSS 是由用戶提供,進程切換時的保存信息由 processor 執(zhí)行。


5.7.1.1、  三個元素構(gòu)成 TSS 環(huán)境:

1、 TSS descriptor:這個 descriptor 屬于 system descriptor 類型,它的 S (system)位是 0。

  下面列出 TSS descriptors 的類型值:

0001:  16-bit TSS
0011: busy 16-bit TSS
1001:  32-bit TSS
1011: busy 32-bit TSS
---------------------------------------------------
  以上是 x86 下的 TSS descriptor 類型,分為 16 和 32 位 TSS,x64 的 long mode 下 32 位的 TSS descriptor 將變?yōu)?64 位 TSS descriptor。


情景提示:

關(guān)于 TSS 的 busy 與 available 狀態(tài):
 。、 TSS descriptor 的類型指明是 busy 與 available 狀態(tài)。
 。、 TSS descriptor 的 busy 與 available 狀態(tài)由 processor 去控制。即:由 processor 置為 busy 或 avaibable!除了初始的 TSS descriptor 外。

  TSS 的 busy 狀態(tài)主要用來支持任務(wù)的嵌套。TSS descriptor 為 busy 狀態(tài)時是不可進入執(zhí)行的。同時防止 TSS 進程切換機制出現(xiàn)遞歸現(xiàn)象。


2、 TSS selector 以及 TR(Task Register)寄存器

  TR 寄存器的結(jié)構(gòu)與 segment registers 是完全一致的,即:由軟件可見的 selector 部分與 processor 可見的隱藏部分(信息部分)構(gòu)成。
  TR.selector 與 CS.selector 中的 selector 意義是完全一樣的。其 descriptor 的加載也是一樣的。

  即: TR.selector 在 GDT / LDT 中索引查找到 TSS descriptor 后,該 TSS descriptor 將被加載到 TR 寄存的隱藏部分。當(dāng)然在加載到 TR 寄存器之前,要進行檢查通過了才可加載到 TR 寄存器。若加載 non-TSS descriptor 進入 TR 則會產(chǎn)生 #GP 異常。


3、 TSS 塊(Task Status Segment)
  像 code segment 或 data segments 一樣,最終的 TSS segment 由 TSS descriptor 來決定。 TSS descriptor 指出 TSS segment 的 base、limit 及 DPL 等信息。
  TSS segment 存放 eflags 寄存器、GPRs 寄存器及相關(guān)的權(quán)限級別的 stack pointer (ss & sp)、CR3 等等信息。




5.7.1.2、 TSS 機制的建立

  對于多任務(wù) OS 來說,TSS segment 是必不可少的,系統(tǒng)至少需要一個 TSS segment,但是現(xiàn)在的 OS 系統(tǒng)不使用 TSS 機制來進行任務(wù)的切換。

情景提示:
  TSS 存在的唯一理由是:需要提供 0 ~ 2 權(quán)限級別的 stack pointer,當(dāng)發(fā)生 stack 切換時,必須使用 TSS 提供的相應(yīng)的 stack pointer。
  但是:若提供空的 TSS segment,或者可以考慮以直接傳遞 stack pointer 的方式實現(xiàn) stack 切換,即便是這樣設(shè)計 processor 要讀取 TSS segment 這一工作是必不可少的。



下面的指令用來建立初始的 TSS segment:
  LTR word ptr [TSS_Selector]                /* 在 [TSS_selector] 提供 TSS selector */
或:LTR ax                                               /* 在 ax 寄存器里提供 TSS selector  */

  ltr 指令使用提供的 selector 在 GDT / LDT 里索引查找到 TSS descriptor 后,加載到 TR 寄存器里。初始的 TSS descriptor 必須設(shè)為 available 狀態(tài),否則不能加載到 TR。processor 加載 TSS descriptor 后,將 TSS descriptor 置為 busy 狀態(tài)。




5.7.1.3、  TSS 進程切換的過程

  當(dāng)前進程要切換另一個進程時,可以使用 2 種 selector 進行:使用 TSS selector 以及 Task gate selector(任務(wù)門符)。

如:
  call 0x2b:0x00000000          /* 假設(shè) 0x2b 為 TSS selector */
     call 0x3b:0x00000000          /* 假設(shè) 0x3b 為 Task-gate  selector */


  TSS 提供的硬件級進程切換機制較為復(fù)雜,大多數(shù) OS 不使用 TSS 機制,是因為執(zhí)行的效能太差了。上面的兩條指令的 TSS 進程切換的過程如下:


1、使用 TSS selector  

  call 0x2b:0x00000000        /* 0x2b 為 TSS selector */

  這里使用 jmp 指令與 call 指令會有些差別,call 允許 TSS 進程切換的嵌套,jmp 不允許嵌套。


(1)processor 使用 TSS selector (0x2b) 在 GDT 索引查找第 5 個 descriptor

(2)processor 檢查找到的 descriptor 類型是否是 TSS descriptor,不是的話將產(chǎn)生 #GP 異常。是否為 available TSS,若目標(biāo) TSS descriptor 是 busy 的話,同樣將產(chǎn)生 #GP 異常。

(3)processor 進行另一項檢查工作:權(quán)限的檢查,CPL <= DPL 并且 selector.RPL <= DPL 即為通過,否則產(chǎn)生 #GP 異常。

(4)當(dāng)前進程的執(zhí)行環(huán)境被保存在當(dāng)前進程的 TSS segment 中。

情景提示:
  在這一步里,此時還沒發(fā)生 TSS selector 切換,processor 把當(dāng)前進程的環(huán)境信息保存在當(dāng)前的 TSS segment 中。


(5)這里發(fā)生了 TSS selector 切換。新的 TSS selector 被加載到 TR.selector,而新的 TSS descriptor 也被加載到 TR 寄存的隱藏部分。

情景提示:
 。ǎ保┻@里,processor 還要將舊的 TSS selector 保存在當(dāng)前的 TSS segment(新加載的 TSS)中的 link 域。這個 TSS segment 中的 link 其實就是 old TSS selector 域,用來進程返回時獲得原來的 TSS selector 。從而實現(xiàn)任務(wù)的嵌套機制。
 。ǎ玻﹑rocessor 將當(dāng)前 eflags 寄存器的 NT(Nest Task)標(biāo)志位置為 1,表明當(dāng)前的進程是嵌套內(nèi)層。


(6)processor 從當(dāng)前的 TSS segment 取出新進程的執(zhí)行環(huán)境,包括:各個 selector registers(segment registers)、GPRs、stack pointer (ss & sp)、CR3 寄存器以及 eflags 寄存器等。
  在這一步,在加載 selectors 進入 segment registers 之前,還必須經(jīng)過相關(guān)的 selector & descriptor  的常規(guī)檢查以及權(quán)限檢查。通過之后才真正加載。否則同樣產(chǎn)生 #GP 異常。

情景提示:
  processor 還要做另一項工作,就是:將新進程的 TSS descriptor 置為 busy 狀態(tài)。使得新進程不能重入。


(7)processor 從當(dāng)前的 CS:RIP 繼續(xù)往下執(zhí)行,完成這個 TSS 進程的切換。這個 CS: RIP 就是新加載的新進程的 cs : rip

---------------------------------------------------------------------------------------
  從上面的過程可以看出,使用 TSS 進程切換機制異常復(fù)雜,導(dǎo)致進程切換的效能太差了。比使用 call gate 以及 trap gate 慢上好多。若當(dāng)中發(fā)生權(quán)限的改變,還要發(fā)生 stack 切換。
  進程的返回同樣復(fù)雜。同樣需要這么多步驟,總結(jié)來說,主要的時間消耗發(fā)生在新舊進程的信息保存方面。




2、 使用 task gate selector
  
  另一種情況是使用 task gate selector 進行 TSS 進程切換,使用 task gate selector 除了可以 call/jmp 外,還可用在中斷機制上,下面的兩種情況:

  call 0x3b:0x00000000            /* 0x3b 為 task gate selector */
或:int 0x3e                              /* 假設(shè) 0x3e 是 task gate 的向量 */


  這兩種情形差不多,除了一些細(xì)微的差別外,不過是觸發(fā)的機制不同而已。

  processor 在 GDT 索引查找到的是一個 task gate descriptor,這個 task gate descriptor 中指出了目標(biāo)的 TSS selector 。processor 從 task gate descriptor 里加載 TSS selector,剩下的工作和使用 TSS selector  進行切換進程是一致。
  processor 訪問 task gate descriptor 僅需對 task gate descriptor 作出權(quán)限檢查:CPL <= DPL 并且 RPL <= DPL。在這里不需要作出對 TSS descriptor 的 DPL 權(quán)限進行檢查。


  gate descriptor 機制提供了一層間接的訪問層,主要用來控制權(quán)限的切換。

實際上:
  對于 call 0x2b:0x00000000 這條指令,processor 并不知道這個 selector 是 TSS selector 還是 task gate selector,在查找到 descriptor 后,processor 查看這個 descriptor 的 type 才能確定是 TSS selector 還是 task gate selector。



最后需注意:
  (1)使用 jmp 指令進行轉(zhuǎn)移,processor 不會將 eflags 中 NT 標(biāo)志位置 1
  (2)使用中斷機制下的 TSS 進程切換,processor 將不作任務(wù)的權(quán)限檢查動作。





5.7.1.4、 TSS 進程的返回

  從 TSS 機制切換的進程在執(zhí)行完后使用 iret 指令返回原進程進,同樣會發(fā)生新舊 TSS segment 的更新動作。

  進程通過使用 ret 返回時,processor 將不會從嵌套內(nèi)層返回到的嵌套外層進程,也就是不會返回原進程。processor 對 ret 指令的處理,只會從 stack  pointer(ss : esp) 取返回地址。



對于使用進程使用了 iret 中斷返回指令時:

(1)processor 將會檢查當(dāng)前的 eflags.NT 標(biāo)志位是否為 1,也就是檢查當(dāng)前進程是否處于嵌套的內(nèi)層。

(2)eflags.NT = 1,processor 將從當(dāng)前 TSS segment 中的 link(old TSS selector)域中取出原來進程的 TSS selector。

(3)processor 將不作任何的權(quán)限檢查,TSS selector 被加載到 TR.selector,TSS descriptor 同時被加載到 TR 的隱藏部分。

(4)processor 將清除當(dāng)前的 eflags.NT 為 0。若是使用 ret 指令返回的,processor 是不會清 eflags.NT 為 0

(5)從 TSS segment 中加載新的進程執(zhí)行環(huán)境,從新的 CS:EIP 處繼續(xù)執(zhí)行。 將原來的 TSS descriptor 重新置為 available 狀態(tài),使得可以再次進入。


-----------------------------------------------------------------------------

  由上可得,processor 遇到 ret 指令時,是不會對 eflags.NT 進行檢查的。而使用 iret 指令,processor 將對 eflags.NT 進行檢查。





:wink:

[ 本帖最后由 mik 于 2009-2-25 15:47 編輯 ]

論壇徽章:
0
13 [報告]
發(fā)表于 2009-02-25 16:13 |只看該作者
TSS 的題外話:使用 TSS 機制在任何權(quán)限下進行隨意的切換


  
  利用 TSS  機制可以進行任意權(quán)限級別的隨意切換是基于:

(1)在任何權(quán)限下可以更改 eflags.NT 標(biāo)志位。

(2)使用中斷返回指令 iret 進行切換到更高級或更低級權(quán)限的代碼。


如下:
  pushfd                                       /* 這條指令可以在 3 級執(zhí)行 */
      or dword ptr [esp], 0x4000           /* 置 eflags.NT 為 1 */
      popfd                                         /* 寫 eflags */
      ... ...
      iret                                          /* 使用 iret 進行切換到高級或低級代碼 */

--------------------------------------------------------------------------

基于以上所述成立的條件是:

(1)在當(dāng)前 TSS segment 中的 link(old TSS selector)指出另一個 TSS selector

(2)從這個 TSS selector 所索引出 TSS descriptor ,最終從這個 TSS descriptor 加載的 TSS segment 中加載權(quán)限高或權(quán)限低的 selectors,包括 cs selector 、ds selector 以及 ss selector ,從而實現(xiàn)任何權(quán)限的切換。


這里唯一的障礙是:
  需要在 0 級權(quán)限下首先建立一個可用的 TSS segment 環(huán)境,而 TSS segment 的 link 域里有個可用的 TSS selector。LTR 指令需要在 0 級權(quán)限下使用。



  

   

論壇徽章:
0
14 [報告]
發(fā)表于 2009-03-03 23:55 |只看該作者
5.7.2、  LDT descriptor



  顯然,GDT(global descriptor table)是系統(tǒng)與所有進程共用的。相對于 LDT(local descriptor table)則是進程獨享的。GPRs、selector registers、stack pointers、eflags、LDT descriptor、CR3 構(gòu)成了一個進程的執(zhí)行環(huán)境。
  TSS segment 包含了上述幾個環(huán)境資源。LDT 是進程獨享的一個資源,是基于進程生命周期內(nèi)該 LDT 進程外不可見的。每個進程有自己的 LDT (前提是系統(tǒng)使用了 LDT 機制)。
  實際上,使用了 LDT 機制等于使用了 TSS 機制。TSS 機制早已被絕大多數(shù) OS 所拋棄了。這無疑是 LDT 機制被絕大多數(shù) OS 舍棄。然而,LDT 雖然是進程獨享的,但另一方面,使得多個進程可以共享內(nèi)存。通過傳遞同個的 LDT descriptor 就可以在多個進程中共享內(nèi)存區(qū)域。如:每個進程的 TSS segment 中的 LDT descriptor 設(shè)為同一個 descriptor。



5.7.2.1、 LDT 的使用

1、LDT 的初始化
  操作系統(tǒng)在初始化時,可以使用 LLDT 指令建立一個 LDT。 LLDT 須要 0 級權(quán)限,所以在用戶進程方面不能使用 LLDT 指令建立 LDT。
 
 
用法示例:
 
   LLDT ax                                     /* ax 是 LDT descriptor selector*/
或:
   LLDT word ptr [LDT_desc]        /*  內(nèi)存 [LDT_desc] 存放著 LDT descriptor selector */


很顯然,這里的 LDT descripotr selector 結(jié)構(gòu)應(yīng)該是:

  XXXXXXXXXXXXX 0 00

在 GDT 中對應(yīng)的 LDT descriptor entry。


2、用戶進程中的 LDT
  通過 TSS 切換的進程可以在 TSS segment 中指出 LDT descriptor selector。在進程切換后,processor 會自動執(zhí)行 load LDT descriptor 的動作。這個 LDT descriptor selector 結(jié)構(gòu)和上述的一樣的。同樣要在 GDT 查找 LDT descriptor。

  在這里,如果多個進程的 TSS segment 中的 LDT descriptor selector 設(shè)為同一個 selector 的話,等同于多個進程共享同一個 LDT,起共享內(nèi)存作用。



5.7.2.2、 LDT descriptor 的加載
  
  LDT descriptor 的加載模式和 TSS descriptor 的加載模式完全一樣。

  如同 TSS descriptor 加載到 TR 寄存器一樣,LDT descriptor 被加載到 LDTR 寄存器。LDTR 寄存器與 TR 寄存器的結(jié)構(gòu)也完全一致。包括:selector 域、attribute 域、limit 域以及 base 域。

情景提示:
  1、實際上,segment registers、LDTR 以及 TR 的結(jié)構(gòu)都是一樣的。而 GDTR 與 IDTR 則是一樣的。
 。、segment registers、LDTR 以及 TR 的加載方式也是一樣的。而 GDTR 與 IDTR 的加載方面是一樣的。GDTR 與 IDTR 是需要操作系統(tǒng)初始化,代表 GDT 與 IDT 兩個 descriptor table 結(jié)構(gòu)必須要建立。





:wink:

[ 本帖最后由 mik 于 2009-3-12 17:17 編輯 ]

論壇徽章:
0
15 [報告]
發(fā)表于 2009-03-12 17:37 |只看該作者
5.7.3、 使用 Gate 構(gòu)建保護模式下 protected 核心


  x86 下 segment 保護核心就是 gate 機制,x64 的 long 模式下 segment 保護有所弱化,AMD 號稱 long 模式取消了 segment 機制,實際上,現(xiàn)階段的的 x64 體系中,segment 機制是不可取消的。只不過是將平坦內(nèi)存模式從軟件層移到硬件層,等取于取消了 segment 機制。
  現(xiàn)在的操作系統(tǒng)都將 protected 重心放在了 paging 階段,x64 體系從硬件層體現(xiàn)了這個思想。



5.7.3.1、 gate 是什么

  gate 機制體現(xiàn)在 gate descriptor 的設(shè)置,顯然,gate descriptor 像是一道通關(guān)令符。顧名思義,門是通過另一片天地的必經(jīng)之路。這片天地通常會得到更多的資源,這片天地通常就是系統(tǒng)的核心代碼部分。
  gate descripotr 門符就是指引通往這片天地的鑰匙。有權(quán)限獲得門符就可以訪問更底層的代碼。


  gate descriptor 的作用相當(dāng)于 C 語言里的指針,并且這個指針就是函數(shù)指針。

如下:

void foo()
{
        ... ...
}

int main()
{
        void (*pf)() = foo;
        ... ...
        
        pf();             /* call gate 類似 */
        ... ...
}


  gate 機制是一種間接的轉(zhuǎn)移控制方式。gate 的主要作用是用來檢查權(quán)限、切換權(quán)限。上面的 c 代碼中,函數(shù)指針 pf 相當(dāng)一個 call gate descritpor。gate descriptor 結(jié)構(gòu)里指出了真正要跳轉(zhuǎn)代碼的地方。


有以下幾種 gate 類型:
● call gate
● interrupt gate
● trap gate
● task gate



上面的圖是這幾種 gate descriptor 的格式。


1、在 task gate descriptor 里,關(guān)鍵的元素就是 TSS selector,這個 TSS selector 給出目標(biāo)進程的 TSS selector,通過使用 task gate descriptor 達到使用 TSS 來進行進程的切換。

2、可見 interrupt gate descriptor 與 trap gate descriptor 的格式是完全一致的,它們的匹別只是 type 的不同。

3、而 call gate descriptor 與 interrupt/trap gate descriptor 的區(qū)別只是,使用 call gate 可以傳遞總共 31 個參數(shù)。




5.7.3.2、  如何使用 call gate 傳遞參數(shù)

  在 call gate descriptor 的 parameter count 部分里指出了參數(shù)的個數(shù)。這個參數(shù)是告訴目標(biāo)代碼將要有多少個參數(shù)傳遞過來。

看下面的例子:

/* caller */

push param1                     /* parameter */
push param2
push param3

call 0x20:00000000              /* call gate */

... ...


在調(diào)用方里使用 call gate 進行切換。caller 先壓入了 3 個參數(shù),然后通過 call gate 來調(diào)用子例程


/* callee */

... ...

ret 0x0c


子例程 callee 完成工作后,很正常地 ret 返回。

那么,當(dāng)發(fā)生 stack 切換時,即:caller 在 CPL =3 下, callee 在 CPL = 0 下,這時會發(fā)生 stack 的切換。

此時,processor 會做相當(dāng)多的必要工作,在假設(shè)通過權(quán)限的檢查下:

1、首先從 TSS segment 里得到 0 級下的 stack 指針(即:SS 和 ESP)加載到 SS 以及 ESP。這時屬于 0 級下的 stack 空間了。

2、將原來的 SS 及 ESP 保存到新的 stack 里,也就是壓入舊的 SS 及 ESP。

3、然后,這里根據(jù) call gate descriptor 里的 parameter count 參數(shù)個數(shù),從舊的 stack 里復(fù)制參數(shù)到新的 stack 里。在這個例子里是 3 個參數(shù),也就是依次壓入 param1、param2 及 param3 在 stack 上。
  在這一步里就實現(xiàn)了傳遞參數(shù)。


4、然后,再保存返回指針(即:CS 及 EIP)。

5、在 callee 返回時執(zhí)行 ret 0x0c 時,pop 出 CS 及 EIP,ret 0x0c 會消去壓入的 12 個字節(jié)的。

6、pop 出 原來的 stack 指針(SS 及 ESP)。從而 0 級的 stack 恢復(fù)正常。


  使用 call gate 傳遞參數(shù),是一種 caller 與 callee 的約定方式,caller 壓入?yún)?shù),并明確告訴 callee 有多少個參數(shù)。而 callee 必須負(fù)責(zé)做消除 stack 工作。
  這個例程的使用參數(shù)一旦定下來,caller 與 callee 就不能改變。若一方改變了這種約定,就會造成 stack 混亂。






:wink:

[ 本帖最后由 mik 于 2009-3-21 23:52 編輯 ]

論壇徽章:
0
16 [報告]
發(fā)表于 2009-03-22 00:44 |只看該作者
5.7.3.3、 gate 的使用方法

  gate descriptor 給出了目標(biāo)代碼的訪問途徑。



上面給出一個直觀的訪問途徑圖。這個途徑就是:

1、gate descriptor 的 selector 給出目標(biāo)代碼的 code segment descriptor
2、由目標(biāo)代碼 code segment descriptor 的 base address 得出代碼的 base
3、這個 base 加上 gate descriptor 的 offset 值,最終得到代碼的入口點。

用 C 代碼描述為:

void do_call_with_gate(selector_t call_gate_descriptor)
{
        code_descriptor = get_descriptor(call_gate_descriptor.selector);
        base = code_descriptor.base;

        void (*pf)() = (void(*)()) base + call_gate_descriptor.offset;

        pf();

}




在用戶代碼中使用如下指令:

  call  0x20:00000000                 /*  通過 call gate 調(diào)用 */
或:
  jmp 0x20:00000000               

---------------------------------------------------------------
  上面這條指令是 far call 指令格式:call cs:eip 這種形式。 0x20 為 call gate descriptor selector,在這里 0x000000000 是無意義的。只是為了完整這條指令格式,可以使用任意一個值。
  在 gate descriptor 格式里,高 16 位和低 16 位組成一個 32 位的 offset 值。這個值就是入口地址。在絕大多數(shù)的 OS 里使用的平坦內(nèi)存模式下,base 為 0,那么,這個 offset 就是最終的服務(wù)例程的入口點。

論壇徽章:
0
17 [報告]
發(fā)表于 2009-03-22 20:49 |只看該作者
話題 6、 x64 體系下的 segment 情形


  

6.1、 x64 下的物理資源及系統(tǒng)數(shù)據(jù)結(jié)構(gòu)


6.1.1、 segment registers

  x64 體系在硬件級上最大限度地削弱了 segmentation 段式管理。采用平坦內(nèi)存管理模式,因此體現(xiàn)出來的思想是 base 為 0、limit 忽略。
  但是,x64 還是對 segmentation 提供了某種程度上的支持。體現(xiàn)在 FS 與 GS 的與眾不同。
  segment registers 的 selector 與原來的 x86 下意義不變。


在 64 bit 模式下:

(1)code register(CS)
  ● CS.base = 0(強制為 0,實際上等于無效)
  ● CS.limit = invalid
  ● attribute:僅 CS.L 、CS.D、CS.P、CS.C 以及 CS.DPL 屬性是有效的。

情景提示:
  64 bit 模式下的 code segment descriptors 中的 L 位、D 位、P 位、C 位以及 DPL 域是有效的。code segment descriptor 加載到 CS 后僅 CS.L 、CS.D、CS.P、CS.C 以及 CS.DPL 屬性是有效的。


  在 compatibility 模式下 code segment descriptor 和 CS 寄存器與原來 x86 意義相同。


(2)data registers (DS、ES 以及 SS)
  ● DS.base = 0(強制為 0,實際上等于無效)
  ● DS.limit = invalid
  ● DS.attribute = invalid:所有的屬性域都是無效的。

  data registers 的所有域都是無效的。data segment 的 attribute 是無效的,那么也包括 DPL、D/B 屬性。

  在 64 bit 模式下,所有的 data segment 都具有 readable/writable 屬性,processor 對 data segment 的訪問不進行權(quán)限 check 以及 limit 檢查。


(3)FS 與 GS
  ● FS.base 是完整是的 64 位。
  ● FS.limit = invalid
  ● FS.attribute = invalid

  與其它 data registers 不同的是,F(xiàn)S 與 GS 的 base 是有效的。支持完整的 64 位地址。但是 limit 和 attribute 依舊無效的。


1、為 FS 和 GS 加載非 0 的 64 位 base 值,使用以下指令:
  
  mov fs, ax

  pop fs

--------------------------------------------  
  這條指令只能為 fs 提供 32 位的 base 值,這根本的原因是:data segment descriptor 提供的 base 是 32 位值。在 x64 里的 segment descriptor 是 8 個字節(jié)。也就是 base  是 4 個字節(jié)。通過 selector 加載 base 值,只能獲取 32 位地址值。


2、為 fs 和 gs 提供 64 位地址值,可以使用以下指令:

  mov ecx, C0000100                   /* FS.base msr 地址 */
  mov edx, FFFFF800
  mov eax, 0F801000                    
   wrmsr                                        /* 寫 FS.base */
--------------------------------------------------
  上面代碼為 FS.base 提供 0xFFFFF8000F801000 地址。


  mov ecx, C0000101                   /* GS.base msr 地址 */
  mov edx, FFFFF800
  mov eax, 0F801000                    
   wrmsr                                        /* 寫 GS.base */
--------------------------------------------------
  上面代碼為 GS.base 提供 0xFFFFF8000F801000 地址。


  另一種方法是使用 swapgs 指令,這條指令將 kernelGS 地址與 GS.base 交換。
  



6.1.2、 descriptors 結(jié)構(gòu)

  x64 體系已經(jīng)不提供對 segmentation 的支持(或者說最大程度削弱了),對于 segment descriptor 來說,還是停留在 x86 的階段,絕大部分的功能已經(jīng)去掉。但是對于 system descriptor 來說,它是被擴展為 16 個字節(jié),是 128 位的數(shù)據(jù)結(jié)構(gòu)。
  因此,descriptors 結(jié)構(gòu)要分兩部分來看。

1、segment descriptors
  包括 code segment descriptor 和 data segment descriptor,code segment descriptor 除這幾個屬性: P 位、C 位、D 位、L 位以及 DPL 外,其它都是無效的(當(dāng)然 code segment descriptor 的 S 位為 0 表示 segment descriptor,code / data 位為 1 表示 code segment)。
  data segment descriptor 除了 P 屬性外,其它都是無效的(當(dāng)然 data segment descriptor 的 S 屬性為 0,code/data 屬性為 0)。
  segment descriptor  還是 8 個字節(jié) 64 位的數(shù)據(jù)結(jié)構(gòu),沒有被擴展為 16 個字節(jié),根本的原因是 base 域是無效的。



2、 system descriptors
  包括 LDT descriptor、TSS descriptor 。這些 descriptor 被擴展為 16 個字節(jié)共 128 位。descriptor 的 base 域被擴展為 64 位值。用來在 64 位的線性地址空間中定位。

  在 64 bit 模式下,LDT / TSS descriptor 被擴展為 64 位的 descriptor,base 是 64 位值。在 compatibility 模式下,LDT / TSS 依舊是 32 位的 descriptor!
  


3、 gate descriptor
  long mode 下不存在 task gate。所有的 gate(call、interrupt / trap) 都 64 位的。gate 所索引的 code segment 是 64 位的 code segment(L = 1 && D = 0)



情景提示:
  1、long mode 下的 segment descriptor 與 x86 原有的 segment descriptor 格式完全一致,只是在 64 bit 模式中 descriptor 的大部分域是無效的。
 。、64 bit 模式下的 system descriptor 被擴展為 16 個字節(jié)。由于 system descriptor 中的 base 是有效的,base 被擴展為 64 位,故 system descriptor 被擴展為 128 位。





6.1.3、 descriptor table

1、long mode 下的 GDT / LDT 表

試想一下,以下情景:
  當(dāng) processor 處于 long mode 下,而要執(zhí)行的目標(biāo)代碼是 32 位的,也就是說 processor 將要進入 compatibility mode(兼容模式)去執(zhí)行 x86 的 32 位代碼,此時變得有玄妙 ... ...


 。薄⑹紫,processor 處于 long mode,這表明此時:processor 既可以執(zhí)行 64 位代碼也可以進入 compatibility mode 去執(zhí)行 32 位代碼。什么情形下進入 compatibility mode 呢?這是根據(jù)目標(biāo)代碼的 descriptor 的 L 屬性,目標(biāo)代碼的 descriptor 加載進入 CS 后,即 CS.L 決定是 64 bit mode 還是 compatibility mode。
  當(dāng) CS.L = 1 時,processor 處于 64 bit mode, CS.L = 0 時,processor 處于 compatibility mode。

 。、其次,一個既可執(zhí)行 64 位代碼,又可 32 位代碼的 64 位 OS ,它的核心 kernel 及系統(tǒng)服務(wù)例程、相關(guān)的系統(tǒng)庫是運行在 64 bit 模式下的。原有的 32 位代碼運行 compatibility 模式下。
  所以,在 GDT 表中可能同時存在 32 位的 descriptor 和 64 位的 LDT/TSS descriptor、64 位的 call gate descriptor。

  3、最后,processor 是怎樣識別哪個是 32 位的 descriptor?哪個是 64 位的 call gate descriptor ?在 32 與 64 位 descriptor 相互存在的 descriptor table 里又是如何去正確讀取所要的 descriptor ?


-----------------------------------------------------------------------------------------------
  在 long mode 下所有的 gate 都是 64 位的,所有的 segment descriptors 都是 32 位的。processor 根據(jù) descriptor 的 types 來判斷哪些是 64 位,哪些是 32 位。


  這樣需要解決一個 32 位 descriptor 與 64 位 descriptor 重疊的問題,思考以下的指令:

call [call_gate]             /* call gate */


  若 [call_gate] 里放著的 selector 是 0x20,若它是 64 位的 call gate descriptor selector。那么 processor 將進入 64 位模式執(zhí)行 64 位代碼。這個 selector 中的 SI 值是 4,所以 GDT 表中的第 4 項是個 64 位的 call gate descirptor。
  這個 64 位的 call gate descriptor 結(jié)構(gòu)有 128 位寬。64 位的 base 中,低 32 位 base 在前 8 個字節(jié)里,高 32 位 base 在后 8 個字節(jié)里的前2 個字節(jié)。


在這種情形下,當(dāng)程序中,使用了以下指令,意圖去訪問 32 位的 code segment descriptor 時,就會產(chǎn)生問題:
  
  call 0x28:00000000                  /* 意圖訪問 32 位的 code segment */

  這個 selector 的 SI 是 5,所以 processor 剛好訪問到 64 位的 call gate descriptor 的高半部分。這個高半部分是 base 的高 32 位值。當(dāng)程序中以 32 位 code segment descriptor 形式訪問 64 位的 call gate descriptor 高半部分,這時 32 位的 code segment descriptor 與 64 位 call gate 的高半部分重疊了,這根本不是想要訪問的 32 位 code segment descriptor,這就產(chǎn)生了不可預(yù)測的結(jié)果。

  也就是說:以 64 位 gate 的高半部分作為 32 位的 descriptor 訪問將現(xiàn)出不可預(yù)制的結(jié)果。

情景提示:
  這個原因產(chǎn)生的根本原因是:GDT 的索引是固定為以 8 字節(jié)寬度進行索引。在 64 位模式下,不會以 16 字節(jié)為寬度進行索引,還是以 8 字節(jié)寬度進行索引,這導(dǎo)致 32 位的 descriptor 可能會與 64 位 descriptor 部分重疊了。


  解決這個問題的設(shè)計思想是,將 64 位的 gate descriptor 或 LDT descriptor、TSS descriptor 的高半部分的對應(yīng) descriptor 的 type 的域置為 0000。
  當(dāng) type = 0000 時,表示這個 descriptor 是非法的,這樣會引發(fā) #GP 異常。

  所以,當(dāng)上述的情形下,64 位的 call gate desciptor 的高半部分的 type 域定義為 0000 時,以 32 位 descriptors 方式訪問 64 位 call gate 的高半部分時,將產(chǎn)生 #GP 異常。這樣將避免產(chǎn)生不可預(yù)測的結(jié)果改變產(chǎn)生 #GP 異常,從而提醒軟件設(shè)計人員進行更改。


這種實施策略相當(dāng)于:

char *p = 0;           
*p = 'a';                      /* 產(chǎn)生異常 */
--------------------------------------------
  OS 將反饋給程序員這將產(chǎn)生異常,目的是將不可預(yù)測的結(jié)果改為可預(yù)測的錯誤結(jié)果。從而避免錯誤。




2、 long mode 下的 IDT 表

  前面提到,在 long mode 下:GDT/LDT 中是以 8 個字節(jié)進行索引的。那么:在 IDT 中則是以 16 個字節(jié)索引的。

情景提示:
  1、GDT / LDT 是以 8 個字節(jié)進行索引 descriptors。
 。、IDT 是以 16 個字節(jié)進行索引 descriptors。



造成這種在不同 descriptor table 中按不同 size 進行索引的根本原因是:

  1、在 GDT / LDT 中,可以同時存放 32 位與 64 位的 descriptors,這些 descriptors 包括:32 位的 segment descriptors、64 位的 system descriptors(LDT descriptors、TSS descriptors),還有就是 64 位的 call gate descriptors。
  所以,在 GDT / LDT 中只能以原來的 8 個字節(jié)進行索引,那么在 64 位的 system descriptors 中,必須在其高 8 字節(jié)的 type 屬性里設(shè)為: type = 0000 以防止 32 位 descriptors 與 64 位 descriptors 重疊而產(chǎn)生問題。

 。、在 IDT 中,只能存放 64 位的 descriptors,所以不像 GDT / LDT 那樣需要兼容 32 位的 descriptors。因此,在 IDT 中固定以 16 個字節(jié)進行索引 descriptor entrys。

  IDT 是不能存放 call gate descriptors 的,只能存放 interrupt /trap descriptors 。task gate 在 long mode 下不存在。














:wink:

[ 本帖最后由 mik 于 2009-4-11 02:54 編輯 ]

論壇徽章:
0
18 [報告]
發(fā)表于 2009-03-29 01:19 |只看該作者
6.1.4、  long mode 下的 call gate


6.1.4.1、 64 位的 call gate descriptor 中已經(jīng)不支持 parameter count 域,offset 域被擴展至 64 位 base 值。

情景提示:
  64 位的 call gate descriptor 的中 selector 域必須是一個 64 位代碼的 selector,也就是說:這個 selector 指向的 code segment descriptor 中的 L 屬性必須是 1,并且 default operand size 為 32 位,即:D 屬性為 0。否則將產(chǎn)生 #GP 異常。(L = 1 && D = 0)
  若要轉(zhuǎn)到 32 位代碼,須使用 32 位的 call gate descriptor。


  由于 64 位的 call gate descriptor 中不支持 parameter count 域,所以在 long mode 下,processor 不支持自動復(fù)制參數(shù)的行為(從 caller 的 stack 復(fù)制到 callee 的 stack 中)。

那么,在 long mode 下如何使用 call gate 調(diào)用例程時,如果確實需要傳遞參數(shù),又是如何傳遞參數(shù)呢?  

  在 stack 不進行切換的情況下,和一般的例程調(diào)用別無兩樣。在要進行 stack 切換的情形下,原來的 stack 的 ss 和 rsp 值被保存至新的 stack 中(也就是 caller 的 ss 和 rsp 會保存至 callee 的 stack 中)。那么,例程 callee 將直將使用原來的 rsp 去獲取參數(shù)。
  這樣做的根本原因是,在 x64 的 long mode 下在硬件級下使用的是平坦內(nèi)存管理模式,忽略了 segmentation 管理,callee 將可以直接使用 rsp 來獲取參數(shù)。


看看下面的指令的情形:

caller: 
    ... ...
  push param1
  push param2 
    call [call_gate]            /* call gate */
  ... ...


  caller 中用 call gate 進行調(diào)用例程 callee, 假設(shè)這里需要進行 stack 的切換。


callee:

   ret         


  callee 中僅使用 ret 進行返回,無需進行清棧處理。


那么:
  caller 的 ss 和 rsp 將被保存至 callee 的 stack 中,如下:

------------------
     caller's SS       + 24
------------------
    caller's RSP      + 16
------------------
    caller's CS       + 8
------------------
    caller's RIP         <------------   callee's  rsp
------------------
 ... ...
------------------

  在例程 callee 中 [rsp+16] 處獲取 caller's rsp 值,callee 中如下處理:

  push rbp
      mov rbp, rsp
      mov rax, [rbp + 24]           /* get caller's rsp */
      mov rbx, [rax]                   /* get param1  */
      ... ...

      和一般的調(diào)用例程,使用參數(shù)無異,不像 x86 下使用 call gate 調(diào)用例程,processor 會自動產(chǎn)生復(fù)制參數(shù)行為。



6.1.4.2、 前面提過,call gate 只能存放在 GDT / LDT 中,不能放在 IDT 中
  這造成 64 位的 call gate descriptors 的高 8 字節(jié)的 type 屬性必須為 0000,以避免 32 位的 descriptor 與 64 位的 descriptors 重疊在一起。為 0 的 type 是屬于無效的 descriptors 類型,processor 會檢測這個 type 是否為 0,為 0 則是無效的 descriptors。
  這樣的話,想提取 64 位的 descriptors 的高半部分作為 32 位 descriptors 使用就會產(chǎn)生一個 #GP 異常。
  

論壇徽章:
0
19 [報告]
發(fā)表于 2009-03-29 01:59 |只看該作者
6.1.5、  long mode 下的 TSS segment 以及 task gate

  long mode 已經(jīng)不支持使用 TSS 機制進行任務(wù)切換。TSS 必須存在的唯一原因依然是:需要提供每個權(quán)限級別的 stack 指針。但是,由于不支持 TSS 任務(wù)切換機制,所以,long mode 下的 TSS segment 和原來的 TSS segment 有很大的改變。


1、long mode 下的 TSS segment 去掉了必要的執(zhí)行環(huán)境,包括:GRPs 集、Selector Registers 集、eflags 寄存器、CR3 寄存器、指令指針 EIP、LDT selector 以及 Task link。
  這些執(zhí)行環(huán)境在 x86 環(huán)境中是必須的。但是在 x64 的 long mode 下的 TSS segment 中這些環(huán)境要素已經(jīng)沒用處了,x64 的 Tss segment 唯一的作用就是提供 stack pointer。

2、long mode 下的 TSS segment 中的 stack pointer 被擴展至 64 位,SS selector 被拋棄。同時又增加了 7 個 stack pointer。這些新增的 7 個 stack pointer 和原來的 stack pointer 意義和用途都不同 。
  原來的 3 個 stack pointer 意義是代表權(quán)限級別為 0、1、2 的通用 stack pointer,在任務(wù)切換時,若發(fā)生了 stack 切換時相應(yīng)級別的 stack pointer。
  新增的 7 個 stack pointer 是特定用途的 stack pointer,僅用于發(fā)生中斷和異常時使用。這 7 個 stack pointer 意即:Interrupt Stack Table(IST)IST ~ IST7。使用于 interrupt 或 trap gate descriptor 中。在 interrupt/trap gate descriptors 里指出相應(yīng)的 stack pointer 號,從而進入相應(yīng)的 stack。



  由于在 long mode 下不支持 TSS segment 任務(wù)切換機制,所以,在 long mode 下沒有 task gate 存在。當(dāng)然也不支持使用 TSS selector 進行任務(wù)切換
  





:wink:

[ 本帖最后由 mik 于 2009-4-1 16:23 編輯 ]

論壇徽章:
0
20 [報告]
發(fā)表于 2009-04-06 22:37 |只看該作者
6.1.6、 long mode 下的 interrupt/trap gate


  interrupt 與 trap gate 格式是一樣的,只是 descriptor type 不一樣而已。與 x86 的 interrupt / trap gate 的所不同的是:base 擴展為 64 位、額外增加了 IST 域。
  前面提過,由于 interrupt / trap gate 只能放在 IDT 表中,不存在 64/32 位代碼共存的現(xiàn)象,所以,interrupt / trap gate 的高半部分的 type 域不需為 0000,而保留未用。



6.1.6.1、 interrupt gate 與 trap gate 的細(xì)微區(qū)別

  interrupt 與 trap 是在格式上是完全一致,區(qū)別在于:當(dāng)響應(yīng) interrupt gate 時,processor 將 Rflags.IF 清為 0,將中斷標(biāo)志清為 0,表示在 interrupt 例程執(zhí)行完畢之前是不能響應(yīng)其它的中斷(可屏敝中斷)。
  當(dāng)響應(yīng) trap gate 時,processor 不會對 Rflags.IF 標(biāo)志進行修改。表示在執(zhí)行 trap 例程時,可以響應(yīng)其它的中斷。



6.1.6.2、 IST(Intrrupt Stack Table)的使用
  
  新增的 IST 域共 3 位,可表示 1 ~ 7 個 ID 值,代表 IST1 ~ IST7。當(dāng) IST = 0 時,表示無 IST,或者不使用 IST 功能。
  IST1 ~ IST7 是索引 ID 值,在 long mode 下的 64 位 TSS segment 的 IST1 ~ IST7 中進行索引,前面已經(jīng)提過在 TSS segment 中新增了 IST ~ IST7 共 7 個域,每個域為 64 位值,每個 64 位值是 stack pointer (RSP)。
  假如在 interrupt/trap gate descriptor 中的 IST 設(shè)為 2,那么當(dāng)響應(yīng)這個 interrupt/trap 例程時,processor 據(jù)此在 TSS 中索引到 IST2,將 TSS 的 IST2 加載到 rsp 中,從而使用這個特定的 stack pointer 。
  但是,若發(fā)生了權(quán)限的改變,即發(fā)生了 stack 的切換,最終仍是從相應(yīng)權(quán)限的 stack pointer 加載 rsp 值,如:目標(biāo) interrupt 例程是 0 級的代碼,而調(diào)用者為 3 級代碼。這時發(fā)生 stack 的切換,processor 那么將從 RSP0 中加載 rsp。
  
  IST 的價值是為 interrupt / trap 例程提供一個特定的 stack 環(huán)境。這是在未發(fā)生 stack 切換的前提下。IST 為 0 則表示不使用特定的 stack 環(huán)境。



6.1.6.3、 interrupt / trap gate 調(diào)用流程

  long mode 下的 interrupt / trap gate 與 32 位下的調(diào)用流程有很大差別:

1、在 x86 下 32 位的 interrpt / trap gate 的 base(offset) 并不是真正的 interrupt / trap 例程的執(zhí)行入口,執(zhí)行入口首需經(jīng) interrupt/trap gate 的 selector 域得出目標(biāo) code segment 的 descriptor,然后,目標(biāo) code segment descriptor 的 base 值加上 interrupt / trap gate 的提供 offset 值,最終才形成真正的執(zhí)行入口。
  當(dāng)然,現(xiàn)在絕大部分的 OS 已經(jīng)在 code segment descriptor 的 base 設(shè)為 0,實際上等于 interrupt / trap gate 的 offset 就是例程的執(zhí)行入口。

2、在 long mode 下的 intterupt / trap gate 的 base(offset)提供的是真正的例程執(zhí)行入口地址。而 interrupt / trap gate 的 selector 僅僅只是起了權(quán)限檢查的作用。當(dāng)過通了權(quán)限檢查后,直接將 offset 加載到 rip 進行執(zhí)行。
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP