轉載自:https://blog.csdn.net/q1007729991/article/details/52650822,講的非常好,我就稍微寫點提醒自己的,大部分都是借鑒的23333(懶…)
TSS:Task State Segment
一個TSS的結構類似于下圖
typedef struct TSS {
DWORD link; // 儲存前一個 TSS 段選擇子,使用 call 指令切換寄存器的時候由CPU填寫。
// 這 6 個值是固定不變的!!!,用于提權,CPU 切換棧的時候用
DWORD esp0; // 儲存 0 環棧指針
DWORD ss0; // 儲存 0 環棧段選擇子
DWORD esp1; // 儲存 1 環棧指針
DWORD ss1; // 儲存 1 環棧段選擇子
DWORD esp2; // 儲存 2 環棧指針
DWORD ss2; // 儲存 2 環棧段選擇子
// 下面這些都是用來做切換寄存器值用的,切換寄存器的時候由CPU自動填寫。
DWORD cr3;
DWORD eip;
DWORD eflags;
DWORD eax;
DWORD ecx;
DWORD edx;
DWORD ebx;
DWORD esp;
DWORD ebp;
DWORD esi;
DWORD edi;
DWORD es;
DWORD cs;
DWORD ss;
DWORD ds;
DWORD fs;
DWORD gs;
DWORD ldt;
// 這個暫時忽略
DWORD io_map;
} TSS;
它和TRAP_FRAME很像,TSS聽名字是為了儲存任務狀态的,而不是任務切換的!!!
和 gdtr,idtr 這些不同的是,tr 寄存器是段寄存器,之前已經知道的段寄存器有 cs, ds, es, ss, fs, gs 。也知道段寄存器有96位,還做過實驗驗證。tr 寄存器中存放的直接就是描述了TSS段的相關資訊的一個描述符,比如TSS段的基址,大小和屬性。
GDT 表中可以存放多個 TSS描述符,這意味着記憶體中可以存在多份不同的TSS。總有一個 TSS 是在目前使用中的,也就是 tr 寄存器指向的那個 TSS。當使用 call/jmp + TSS段選擇子的時候,CPU做了以下幾件事情。
把目前所有寄存器(TSS結構中有的那些寄存器)的值填寫到目前 tr 段寄存器指向的 TSS 中
把新的 TSS 段選擇子指向的段描述符加載到 tr 段寄存器中
把新的 TSS 段中的值覆寫到目前所有寄存器(TSS結構中有的那些寄存器)中
說白了,它有兩個用途
- 儲存0~3環的SS,ESP,雖然0,1是沒用的
- 通過 call/jmp 指令 可以切換到tr寄存器所存的描述符所指base所指向的TSS結構