14 局部段描述符的使用

参考

https://www.cnblogs.com/wanmeishenghuo/tag/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/

https://blog.51cto.com/13475106/category6.html

 

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

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

 

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

loader.asm的程序如下:

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

 

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

执行结果如下:

 

小结:

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

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

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

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

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

 

  

 

posted on   lh03061238  阅读(283)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示