LDT与GDT类似,为局部描述符表。使用LDT有几个步骤:
1.在GDT中加一个表项,并增加一个描述符,假设为SelectorLDT;
2.像配置GDT表那样,配置好LDT表自己的描述符,并设置好相应的ldt的选择子,选择子有一位标识是ldt还是gdt;
3.加载LDT,使用lldt指令;
4.直接jmp ldt里面的选择子。
跳转到LDT里的代码段,跟用GDT跳转代码段一样,都是通过
jmp Selector
的方式,关键之处在于Selector
里面有一标志位,标志这个选择子是从LDT表中查找,还是从GDT表中查找。
关键代码:
[SECTION .gdt]
; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描述符
......
LABEL_DESC_LDT: Descriptor 0, LDTLen - 1, DA_LDT ; LDT
; GDT 结束
; GDT 选择子
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
......
SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT
; END of [SECTION .gdt]
下面是LDT自己的描述符表
; LDT
[SECTION .ldt]
ALIGN 32
LABEL_LDT:
; 段基址 段界限 属性
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位
LDTLen equ $ - LABEL_LDT
; LDT 选择子
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL
; END of [SECTION .ldt]
上面的SA_TIL
就是标识这个选择子是属于LDT的关键所在。
上面的SelectorLDTCodeA 对应的代码:
; CodeA (LDT, 32 位代码段)
[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子(目的)
mov edi, (80 * 12 + 0) * 2 ; 屏幕第 10 行, 第 0 列。
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov al, 'L'
mov [gs:edi], ax
jmp $
CodeALen equ $ - LABEL_CODE_A
; END of [SECTION .la]
使用LDT:
; 初始化 LDT 在 GDT 中的描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_LDT
mov word [LABEL_DESC_LDT + 2], ax
shr eax, 16
mov byte [LABEL_DESC_LDT + 4], al
mov byte [LABEL_DESC_LDT + 7], ah
; 初始化 LDT 中的描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_CODE_A
mov word [LABEL_LDT_DESC_CODEA + 2], ax
shr eax, 16
mov byte [LABEL_LDT_DESC_CODEA + 4], al
mov byte [LABEL_LDT_DESC_CODEA + 7], ah
; Load LDT
mov ax, SelectorLDT
lldt ax
jmp SelectorLDTCodeA:0 ; 跳入局部任务