第十四课 局部段描述符的使用

  前面我们使用的都是全局段描述符表,现在我们来分析局部段描述符表的使用。

 什么是LDT(Local Descriptor Table)?

  局部段描述符表:

    本质是一个段描述符表,用于定义段描述符

    与GDT类似,可以看做“段描述符的数组”

    通过定义选择子访问局部段描述符表中的元素

局部段描述符的选择子和全局描述符的选择子在结构上是完全一样的,3-15位为描述符索引值,LDT选择子的第二位恒为1,1-0位为RPL。

局部段描述符表就是一段内存,里面的每一项是一个局部段描述符(第0项也是有意义的),用于描述一段内存。

CPU中有一个专用寄存器专门指向局部段描述符表。(先定义一个常量   DA_LDT    equ  0x82),在全局段描述符表中定义局部段描述符表的描述项时,需要用到属性,这个属性就是DA_LDT。

 局部段描述符表的注意事项:

  局部段描述符表需要在全局段描述符表中注册(增加描述项)

  通过对应的选择子加载局部段描述符(lldt)

  局部段描述符表从第0项开始使用(different  from  GDT)

LDT的意义:

  代码层面的意义:

    分级管理功能相同意义不同的段(如:多个代码段),全局段描述符表也是有界限的,如果分段过多,则全局段描述符表有可能不够用。而局部段描述符表不限制描述符的个数。引入这种分级管理描述符的机制,可以定义无数个段。

  系统层面的意义:

    实现多任务的基础要素(每个任务对应一系列不同的段)

 LDT的定义与使用:

  1、定义独立功能相关的段(代码段、数据段、栈段)

  2、将目标段描述符组成局部段描述符表(LDT)

  3、为各个段描述符定义选择子(SA_TIL)

  4、在GDT中定义LDT的段描述符,并定义选择子

 下面给出示例程序,演示局部段描述符的使用。

inc.asm更新如下:

 1 ; Segment Attribute
 2 DA_32    equ    0x4000
 3 DA_DR    equ    0x90
 4 DA_DRW   equ    0x92
 5 DA_DRWA  equ    0x93
 6 DA_C     equ    0x98
 7 DA_CR    equ    0x9A
 8 DA_CCO   equ    0x9C
 9 DA_CCOR  equ    0x9E
10 
11 ; Special Attribute
12 DA_LDT     equ    0x82
13 
14 ; Selector Attribute
15 SA_RPL0    equ    0
16 SA_RPL1    equ    1
17 SA_RPL2    equ    2
18 SA_RPL3    equ    3
19 
20 SA_TIG    equ    0
21 SA_TIL    equ    4
22 
23 ; 描述符
24 ; usage: Descriptor Base, Limit, Attr
25 ;        Base:  dd
26 ;        Limit: dd (low 20 bits available)
27 ;        Attr:  dw (lower 4 bits of higher byte are always 0)
28 %macro Descriptor 3                              ; 段基址, 段界限, 段属性
29     dw    %2 & 0xFFFF                         ; 段界限1
30     dw    %1 & 0xFFFF                         ; 段基址1
31     db    (%1 >> 16) & 0xFF                   ; 段基址2
32     dw    ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
33     db    (%1 >> 24) & 0xFF                   ; 段基址3
34 %endmacro                                     ; 共 8 字节

我们增加了第12行的宏定义。

loader.asm的程序如下:

  1 %include "inc.asm"
  2 
  3 org 0x9000
  4 
  5 jmp ENTRY_SEGMENT
  6 
  7 [section .gdt]
  8 ; GDT definition
  9 ;                                 段基址,       段界限,       段属性
 10 GDT_ENTRY       :     Descriptor    0,            0,           0
 11 CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32
 12 VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32
 13 DATA32_DESC     :     Descriptor    0,    Data32SegLen  - 1,   DA_DR + DA_32
 14 STACK32_DESC    :     Descriptor    0,      TopOfStack32,      DA_DRW + DA_32    
 15 CODE16_DESC     :     Descriptor    0,           0xFFFF,       DA_C
 16 UPDATE_DESC     :     Descriptor    0,           0xFFFF,       DA_DRW
 17 TASK_A_LDT_DESC   :     Descriptor    0,       TaskALdtLen - 1,  DA_LDT
 18 ; GDT end
 19 
 20 GdtLen    equ   $ - GDT_ENTRY
 21 
 22 GdtPtr:
 23           dw   GdtLen - 1
 24           dd   0
 25           
 26           
 27 ; GDT Selector
 28 
 29 Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
 30 VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0
 31 Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
 32 Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL0
 33 Code16Selector    equ (0x0005 << 3) + SA_TIG + SA_RPL0
 34 UpdateSelector    equ (0x0006 << 3) + SA_TIG + SA_RPL0
 35 TaskALdtSelector  equ (0x0007 << 3) + SA_TIG + SA_RPL0
 36 ; end of [section .gdt]
 37 
 38 TopOfStack16    equ  0x7c00
 39 
 40 [section .dat]
 41 [bits 32]
 42 DATA32_SEGMENT:
 43     DTOS                 db    "D.T.OS!", 0
 44     DTOS_OFFSET          equ   DTOS - $$
 45     HELLO_WORLD          db    "Hello World!", 0
 46     HELLO_WORLD_OFFSET   equ  HELLO_WORLD - $$
 47 
 48 Data32SegLen  equ $ - DATA32_SEGMENT
 49 
 50 [section .s16]
 51 [bits 16]
 52 ENTRY_SEGMENT:
 53     mov ax, cs
 54     mov ds, ax
 55     mov es, ax
 56     mov ss, ax
 57     mov sp, TopOfStack16
 58     
 59     mov [BACK_TO_REAL_MODE + 3], ax 
 60     
 61     ; initialize GDT for 32 bits code segment
 62     mov esi, CODE32_SEGMENT
 63     mov edi, CODE32_DESC
 64     
 65     call InitDescItem
 66     
 67     mov esi, DATA32_SEGMENT
 68     mov edi, DATA32_DESC
 69     
 70     call InitDescItem
 71     
 72     mov esi, DATA32_SEGMENT
 73     mov edi, STACK32_DESC
 74     
 75     call InitDescItem
 76     
 77     mov esi, CODE16_SEGMENT
 78     mov edi, CODE16_DESC
 79     
 80     call InitDescItem
 81     
 82     mov esi, TASK_A_LDT_ENTRY
 83     mov edi, TASK_A_LDT_DESC
 84     
 85     call InitDescItem
 86     
 87     mov esi, TASK_A_CODE32_SEGMENT
 88     mov edi, TASK_A_CODE32_DESC
 89     
 90     call InitDescItem
 91     
 92     mov esi, TASK_A_DATA32_SEGMENT
 93     mov edi, TASK_A_DATA32_DESC
 94     
 95     call InitDescItem
 96     
 97     mov esi, TASK_A_STACK32_SEGMENT
 98     mov edi, TASK_A_STACK32_DESC
 99     
100     call InitDescItem
101     
102     ; initialize GDT pointer struct
103     mov eax, 0
104     mov ax, ds
105     shl eax, 4
106     add eax, GDT_ENTRY
107     mov dword [GdtPtr + 2], eax
108 
109     ; 1. load GDT
110     lgdt [GdtPtr]
111     
112     ; 2. close interrupt
113     cli 
114     
115     ; 3. open A20
116     in al, 0x92
117     or al, 00000010b
118     out 0x92, al
119     
120     ; 4. enter protect mode
121     mov eax, cr0
122     or eax, 0x01
123     mov cr0, eax
124     
125     ; 5. jump to 32 bits code
126     jmp dword Code32Selector : 0
127 
128 BACK_ENTRY_SEGMENT:
129         mov ax, cs
130         mov ds, ax
131         mov es, ax
132         mov ss, ax
133         mov sp, TopOfStack16
134         
135         in al, 0x92
136         and al, 11111101b
137         out 0x92, al
138         
139         sti 
140         
141         mov bp, HELLO_WORLD
142         mov cx, 12
143         mov dx, 0
144         mov ax, 0x1301
145         mov bx, 0x0007
146         int 0x10
147         
148         jmp $
149 
150 ; esi    --> code segment label
151 ; edi    --> descriptor label
152 InitDescItem:
153     push eax
154     
155     mov eax, 0
156     mov ax, cs
157     shl eax, 4
158     add eax, esi
159     mov word [edi + 2], ax
160     shr eax, 16
161     mov byte [edi + 4], al
162     mov byte [edi + 7], ah
163     
164     pop eax
165     
166     ret
167     
168 
169 [section .16]
170 [bits 16]
171 CODE16_SEGMENT:
172     mov ax, UpdateSelector
173     mov ds, ax
174     mov es, ax
175     mov fs, ax
176     mov gs, ax
177     mov ss, ax
178     
179     mov eax, cr0
180     and al, 11111110b
181     mov cr0, eax
182     
183 BACK_TO_REAL_MODE:
184     jmp 0 : BACK_ENTRY_SEGMENT
185     
186 Code16SegLen    equ $ - CODE16_SEGMENT
187 
188     
189 [section .s32]
190 [bits 32]
191 CODE32_SEGMENT:
192     mov ax, VideoSelector
193     mov gs, ax
194     
195     mov ax, Stack32Selector
196     mov ss, ax
197     
198     mov eax, TopOfStack32
199     mov esp, eax
200     
201     mov ax, Data32Selector
202     mov ds, ax
203     
204     mov ebp, DTOS_OFFSET
205     mov bx, 0x0C
206     mov dh, 12
207     mov dl, 33
208     
209     call PrintString
210     
211     mov ebp, HELLO_WORLD_OFFSET
212     mov bx, 0x0C
213     mov dh, 13
214     mov dl, 30
215     
216     call PrintString
217     
218     mov ax, TaskALdtSelector
219     lldt ax
220     
221     jmp TaskACode32Selector : 0
222     
223     ;jmp Code16Selector : 0
224 
225 ; ds:ebp   --> string address
226 ; bx       --> attribute
227 ; dx       --> dh : row, dl : col
228 PrintString:
229     push ebp
230     push eax
231     push edi 
232     push cx
233     push dx
234     
235 print:
236     mov cl, [ds:ebp]
237     cmp cl, 0
238     je end
239     mov eax, 80
240     mul dh
241     add al, dl
242     shl eax, 1
243     mov edi, eax
244     mov ah, bl
245     mov al, cl
246     mov [gs:edi], ax
247     inc ebp
248     inc dl
249     jmp print
250     
251 end:
252     pop dx
253     pop cx
254     pop edi
255     pop eax
256     pop ebp
257     
258     ret
259 
260 Code32SegLen    equ    $ - CODE32_SEGMENT
261 
262 [section .gs]
263 [bits 32]
264 STACK32_SEGMENT:
265     times 1014 * 4 db 0
266     
267 Stack32SegLen    equ $ - STACK32_SEGMENT
268 TopOfStack32    equ Stack32SegLen - 1
269 
270 
271 ; ==================================
272 ;        
273 ;        Task A Code Segment
274 ;
275 ;===================================
276 [section .task-a-ldt]
277 ; Task A LDT definition
278 ;                                        段基址                     段界限                段属性
279 
280 TASK_A_LDT_ENTRY:
281 TASK_A_CODE32_DESC    :   Descriptor       0,               TaskACode32SegLen - 1,  DA_C + DA_32
282 TASK_A_DATA32_DESC    :   Descriptor       0,               TaskAData32SegLen - 1,  DA_DR + DA_32
283 TASK_A_STACK32_DESC   :   Descriptor       0,               TaskAStack32SegLen - 1, DA_DRW + DA_32
284 
285 TaskALdtLen        equ   $ - TASK_A_LDT_ENTRY
286 
287 ; Task A LDT  Selector
288 TaskACode32Selector        equ  (0x0000 << 3) + SA_TIL + SA_RPL0
289 TaskAData32Selector     equ     (0x0001 << 3) + SA_TIL + SA_RPL0
290 TaskAStack32Selector    equ  (0x0002 << 3) + SA_TIL + SA_RPL0
291 
292 [section .task-a-dat]
293 [bits 32]
294 TASK_A_DATA32_SEGMENT:
295     TASK_A_STRING        db   "This is Task A", 0
296     TASK_STRING_OFFSET    equ     TASK_A_STRING - $$
297     
298 TaskAData32SegLen    equ $ - TASK_A_DATA32_SEGMENT
299 
300 [section .task-a-gs]
301 [bits 32]
302 TASK_A_STACK32_SEGMENT:
303     times 1024 db 0
304     
305 TaskAStack32SegLen    equ     $ - TASK_A_STACK32_SEGMENT
306 TaskATopOfStack32    equ     TaskAStack32SegLen - 1
307 
308 [section .task-a-s32]
309 [bits 32]
310 TASK_A_CODE32_SEGMENT:
311 
312     mov ax, VideoSelector
313     mov gs, ax
314     
315     mov ax, TaskAStack32Selector
316     mov ss, ax
317     
318     mov eax, TaskATopOfStack32
319     mov esp, eax
320     
321     mov ax, TaskAData32Selector
322     mov ds, ax
323     
324     jmp $
325     
326 TaskACode32SegLen     equ  $ - TASK_A_CODE32_SEGMENT

从271行开始,我们定义了代表LDT段描述符表本身的段,定义了LDT下的代码段、数据段、栈段。在代码段中,我们加载了相应的段寄存器,最终程序停在原地。

在第17行为LDT段描述符表本身占用的内存增加了段描述符项,用来描述这段内存。

第35行增加了LDT段描述符表所在段的选择子。

218-221行,我们添加了三行程序,作用为加载LDT段描述符表,跳转到LDT段描述符表描述的代码段去执行。

执行结果如下:

 

我们在LDT描述的代码段中加入以下打印程序:

在324-329行加入了打印字符串的功能,这个PrintString函数是在全局段描述符表的代码段中定义的。

执行结果如下:

我们看到发生了CPU硬件复位。

因为PrintString函数不是属于LDT中的代码段的,我们直接调用它导致了越界,从而CPU复位。因为现在的选择子是LDT段描述符中的选择子,即使PrintString代表的偏移地址是相同的也会发生错误。

我们将打印相关的函数复制一份到LDT描述符下的代码段中,如下:

  1 %include "inc.asm"
  2 
  3 org 0x9000
  4 
  5 jmp ENTRY_SEGMENT
  6 
  7 [section .gdt]
  8 ; GDT definition
  9 ;                                 段基址,       段界限,       段属性
 10 GDT_ENTRY       :     Descriptor    0,            0,           0
 11 CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32
 12 VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32
 13 DATA32_DESC     :     Descriptor    0,    Data32SegLen  - 1,   DA_DR + DA_32
 14 STACK32_DESC    :     Descriptor    0,      TopOfStack32,      DA_DRW + DA_32    
 15 CODE16_DESC     :     Descriptor    0,           0xFFFF,       DA_C
 16 UPDATE_DESC     :     Descriptor    0,           0xFFFF,       DA_DRW
 17 TASK_A_LDT_DESC   :     Descriptor    0,       TaskALdtLen - 1,  DA_LDT
 18 ; GDT end
 19 
 20 GdtLen    equ   $ - GDT_ENTRY
 21 
 22 GdtPtr:
 23           dw   GdtLen - 1
 24           dd   0
 25           
 26           
 27 ; GDT Selector
 28 
 29 Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
 30 VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0
 31 Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
 32 Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL0
 33 Code16Selector    equ (0x0005 << 3) + SA_TIG + SA_RPL0
 34 UpdateSelector    equ (0x0006 << 3) + SA_TIG + SA_RPL0
 35 TaskALdtSelector  equ (0x0007 << 3) + SA_TIG + SA_RPL0
 36 ; end of [section .gdt]
 37 
 38 TopOfStack16    equ  0x7c00
 39 
 40 [section .dat]
 41 [bits 32]
 42 DATA32_SEGMENT:
 43     DTOS                 db    "D.T.OS!", 0
 44     DTOS_OFFSET          equ   DTOS - $$
 45     HELLO_WORLD          db    "Hello World!", 0
 46     HELLO_WORLD_OFFSET   equ  HELLO_WORLD - $$
 47 
 48 Data32SegLen  equ $ - DATA32_SEGMENT
 49 
 50 [section .s16]
 51 [bits 16]
 52 ENTRY_SEGMENT:
 53     mov ax, cs
 54     mov ds, ax
 55     mov es, ax
 56     mov ss, ax
 57     mov sp, TopOfStack16
 58     
 59     mov [BACK_TO_REAL_MODE + 3], ax 
 60     
 61     ; initialize GDT for 32 bits code segment
 62     mov esi, CODE32_SEGMENT
 63     mov edi, CODE32_DESC
 64     
 65     call InitDescItem
 66     
 67     mov esi, DATA32_SEGMENT
 68     mov edi, DATA32_DESC
 69     
 70     call InitDescItem
 71     
 72     mov esi, DATA32_SEGMENT
 73     mov edi, STACK32_DESC
 74     
 75     call InitDescItem
 76     
 77     mov esi, CODE16_SEGMENT
 78     mov edi, CODE16_DESC
 79     
 80     call InitDescItem
 81     
 82     mov esi, TASK_A_LDT_ENTRY
 83     mov edi, TASK_A_LDT_DESC
 84     
 85     call InitDescItem
 86     
 87     mov esi, TASK_A_CODE32_SEGMENT
 88     mov edi, TASK_A_CODE32_DESC
 89     
 90     call InitDescItem
 91     
 92     mov esi, TASK_A_DATA32_SEGMENT
 93     mov edi, TASK_A_DATA32_DESC
 94     
 95     call InitDescItem
 96     
 97     mov esi, TASK_A_STACK32_SEGMENT
 98     mov edi, TASK_A_STACK32_DESC
 99     
100     call InitDescItem
101     
102     ; initialize GDT pointer struct
103     mov eax, 0
104     mov ax, ds
105     shl eax, 4
106     add eax, GDT_ENTRY
107     mov dword [GdtPtr + 2], eax
108 
109     ; 1. load GDT
110     lgdt [GdtPtr]
111     
112     ; 2. close interrupt
113     cli 
114     
115     ; 3. open A20
116     in al, 0x92
117     or al, 00000010b
118     out 0x92, al
119     
120     ; 4. enter protect mode
121     mov eax, cr0
122     or eax, 0x01
123     mov cr0, eax
124     
125     ; 5. jump to 32 bits code
126     jmp dword Code32Selector : 0
127 
128 BACK_ENTRY_SEGMENT:
129         mov ax, cs
130         mov ds, ax
131         mov es, ax
132         mov ss, ax
133         mov sp, TopOfStack16
134         
135         in al, 0x92
136         and al, 11111101b
137         out 0x92, al
138         
139         sti 
140         
141         mov bp, HELLO_WORLD
142         mov cx, 12
143         mov dx, 0
144         mov ax, 0x1301
145         mov bx, 0x0007
146         int 0x10
147         
148         jmp $
149 
150 ; esi    --> code segment label
151 ; edi    --> descriptor label
152 InitDescItem:
153     push eax
154     
155     mov eax, 0
156     mov ax, cs
157     shl eax, 4
158     add eax, esi
159     mov word [edi + 2], ax
160     shr eax, 16
161     mov byte [edi + 4], al
162     mov byte [edi + 7], ah
163     
164     pop eax
165     
166     ret
167     
168 
169 [section .16]
170 [bits 16]
171 CODE16_SEGMENT:
172     mov ax, UpdateSelector
173     mov ds, ax
174     mov es, ax
175     mov fs, ax
176     mov gs, ax
177     mov ss, ax
178     
179     mov eax, cr0
180     and al, 11111110b
181     mov cr0, eax
182     
183 BACK_TO_REAL_MODE:
184     jmp 0 : BACK_ENTRY_SEGMENT
185     
186 Code16SegLen    equ $ - CODE16_SEGMENT
187 
188     
189 [section .s32]
190 [bits 32]
191 CODE32_SEGMENT:
192     mov ax, VideoSelector
193     mov gs, ax
194     
195     mov ax, Stack32Selector
196     mov ss, ax
197     
198     mov eax, TopOfStack32
199     mov esp, eax
200     
201     mov ax, Data32Selector
202     mov ds, ax
203     
204     mov ebp, DTOS_OFFSET
205     mov bx, 0x0C
206     mov dh, 12
207     mov dl, 33
208     
209     call PrintString
210     
211     mov ebp, HELLO_WORLD_OFFSET
212     mov bx, 0x0C
213     mov dh, 13
214     mov dl, 30
215     
216     call PrintString
217     
218     mov ax, TaskALdtSelector
219     lldt ax
220     
221     jmp TaskACode32Selector : 0
222     
223     ;jmp Code16Selector : 0
224 
225     
226 ; ds:ebp   --> string address
227 ; bx       --> attribute
228 ; dx       --> dh : row, dl : col
229 PrintString:
230     push ebp
231     push eax
232     push edi 
233     push cx
234     push dx
235     
236 print:
237     mov cl, [ds:ebp]
238     cmp cl, 0
239     je end
240     mov eax, 80
241     mul dh
242     add al, dl
243     shl eax, 1
244     mov edi, eax
245     mov ah, bl
246     mov al, cl
247     mov [gs:edi], ax
248     inc ebp
249     inc dl
250     jmp print
251     
252 end:
253     pop dx
254     pop cx
255     pop edi
256     pop eax
257     pop ebp
258     
259     ret
260 
261 Code32SegLen    equ    $ - CODE32_SEGMENT
262 
263 [section .gs]
264 [bits 32]
265 STACK32_SEGMENT:
266     times 1014 * 4 db 0
267     
268 Stack32SegLen    equ $ - STACK32_SEGMENT
269 TopOfStack32    equ Stack32SegLen - 1
270 
271 
272 ; ==================================
273 ;        
274 ;        Task A Code Segment
275 ;
276 ;===================================
277 [section .task-a-ldt]
278 ; Task A LDT definition
279 ;                                        段基址                     段界限                段属性
280 
281 TASK_A_LDT_ENTRY:
282 TASK_A_CODE32_DESC    :   Descriptor       0,               TaskACode32SegLen - 1,  DA_C + DA_32
283 TASK_A_DATA32_DESC    :   Descriptor       0,               TaskAData32SegLen - 1,  DA_DR + DA_32
284 TASK_A_STACK32_DESC   :   Descriptor       0,               TaskAStack32SegLen - 1, DA_DRW + DA_32
285 
286 TaskALdtLen        equ   $ - TASK_A_LDT_ENTRY
287 
288 ; Task A LDT  Selector
289 TaskACode32Selector        equ  (0x0000 << 3) + SA_TIL + SA_RPL0
290 TaskAData32Selector     equ     (0x0001 << 3) + SA_TIL + SA_RPL0
291 TaskAStack32Selector    equ  (0x0002 << 3) + SA_TIL + SA_RPL0
292 
293 [section .task-a-dat]
294 [bits 32]
295 TASK_A_DATA32_SEGMENT:
296     TASK_A_STRING        db   "This is Task A", 0
297     TASK_A_STRING_OFFSET    equ     TASK_A_STRING - $$
298     
299 TaskAData32SegLen    equ $ - TASK_A_DATA32_SEGMENT
300 
301 [section .task-a-gs]
302 [bits 32]
303 TASK_A_STACK32_SEGMENT:
304     times 1024 db 0
305     
306 TaskAStack32SegLen    equ     $ - TASK_A_STACK32_SEGMENT
307 TaskATopOfStack32    equ     TaskAStack32SegLen - 1
308 
309 [section .task-a-s32]
310 [bits 32]
311 TASK_A_CODE32_SEGMENT:
312 
313     mov ax, VideoSelector
314     mov gs, ax
315     
316     mov ax, TaskAStack32Selector
317     mov ss, ax
318     
319     mov eax, TaskATopOfStack32
320     mov esp, eax
321     
322     mov ax, TaskAData32Selector
323     mov ds, ax
324     
325     mov ebp, TASK_A_STRING_OFFSET
326     mov bx, 0x0c
327     mov dh, 14
328     mov dl, 29
329     
330     call TaskAPrintString
331     
332     jmp Code16Selector : 0
333     
334 ; ds:ebp   --> string address
335 ; bx       --> attribute
336 ; dx       --> dh : row, dl : col
337 TaskAPrintString:
338     push ebp
339     push eax
340     push edi 
341     push cx
342     push dx
343     
344 task_print:
345     mov cl, [ds:ebp]
346     cmp cl, 0
347     je task_end
348     mov eax, 80
349     mul dh
350     add al, dl
351     shl eax, 1
352     mov edi, eax
353     mov ah, bl
354     mov al, cl
355     mov [gs:edi], ax
356     inc ebp
357     inc dl
358     jmp task_print
359     
360 task_end:
361     pop dx
362     pop cx
363     pop edi
364     pop eax
365     pop ebp
366     
367     ret
368     
369 TaskACode32SegLen     equ  $ - TASK_A_CODE32_SEGMENT

我们复制了打印函数,在第332行跳转到16位的保护模式,进一步跳转到16位实模式。

执行结果如下:

 

小结:

局部段描述符表用于组织功能相关的段

局部段描述符表需要加载后才能正常使用

局部段描述符表必须在全局段描述符表中注册

通过局部段描述符表的选择子对其进行访问

局部段描述符表时实现多任务的基础

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9477931.html