《80X86汇编语言程序设计教程》十五 任务切换实例

1、  理论知识参考"《80X86汇编语言程序设计教程》十二 任务状态段、控制门和控制转移",演示内容:直接通过TSS段的任务切换、通过任务门的任务切换、任务内特权级的变换及参数传递。实现的逻辑功能是:从Temp任务切换到Demo任务以后显示原任务(Temp)的挂起点EIP的值。

2、  源代码

  “386scd.asm”不再贴上来。参考"《80X86汇编语言程序设计教程》十三 任务内无特权级变换转移实例",演示代码如下:

  1 ;DosTest.Asm
  2 ;任务切换实例
  3 ;逻辑功能:从Temp任务切换到Demo任务以后显示原任务(Temp)的挂起点EIP的值
  4
  5
  6     include    386scd.asm                    ;文件386.scd含有有关结构、宏指令和符号常量定义
  7     .386p
  8
  9 ;------------------------------------------
 10 ;全局描述符表GDT
 11 GDTSeg    segment    para    use16
 12     GDT        label    byte
 13     ;空描述符
 14     dummy      DESCRIPTOR<>
 15
 16     ;规范数据段描述符,存在的可读写数据段
 17     Normal     DESCRIPTOR<0ffffh,0,0,ATDW,0>
 18     Normal_Sel = Normal - GDT
 19     EFFGDT     label    byte
 20
 21     ;演示任务状态段TSS描述符(16位段,DPL = 0,RPL = 0)
 22     DemoTSS    DESCRIPTOR<DemoTSSLen -1,DemoTSSSeg,,AT386TSS,>
 23     DemoTSS_Sel = DemoTSS - GDT
 24
 25     ;演示任务LDT段描述符(16位段,DPL = 0,RPL = 0)
 26     DemoLDTab     DESCRIPTOR<DemoLDTLen-1,DemoLDTSeg,,ATLDT,>
 27     DemoLDT_Sel = DemoLDTab - GDT
 28
 29     ;临时任务任务状态TSS描述符(16位段,DPL = 2,RPL = 0)
 30     TempTSS DESCRIPTOR<TempTSSLen - 1,TempTSSSeg,,AT386TSS + DPL2,>
 31     TempTSS_Sel = TempTSS - GDT
 32
 33     ;临时任务代码段描述符(16位段,DPL = 0,RPL = 0)
 34     TempCode     DESCRIPTOR<0ffffh,TempCodeSeg,,ATCE,>
 35     TempCode_Sel = TempCode - GDT
 36
 37     ;子程序代码段描述符(32位段,DPL = 0,RPL = 3)
 38     SubR     DESCRIPTOR<SubRLen - 1,SubRSeg,,ATCE + D32,>
 39     SubR_Sel = SubR - GDT + RPL3
 40
 41     ;视频缓冲区段描述符,段界限0fffffh(16位段,DPL = 3,RPL = 0)
 42     VideoBuff    DESCRIPTOR<0ffffh,0,0,0f00h + ATDW + DPL3,0>
 43     Video_Sel = VideoBuff - GDT
 44
 45     GDTNum = ($ - EFFGDT)/(size DESCRIPTOR)
 46
 47     ;指向演示任务Demo的任务门(DPL = 3,RPL = 0)
 48     ;ToDemoT    GATE<0,DemoTSS_Sel,0,ATTASKGAT + DPL3,0>
 49     ;ToDemoT_Sel = (ToDemoT - GDT) + TIL
 50
 51     GDTLen = $ - GDT
 52 GDTSeg    ends
 53
 54 ;------------------------------------------
 55 ;演示任务局部描述符表LDT
 56 DemoLDTSeg    segment    para    use16
 57     DemoLDT    label    byte
 58
 59     ;0级堆栈段描述符(32位段,DPL = 0,RPL = 0)
 60     DemoStack0     DESCRIPTOR<DemoStack0Len - 1,DemoStack0Seg,,ATDW + D32,>
 61     DemoStack0_Sel = (DemoStack0 - DemoLDT) + TIL
 62
 63     ;2级堆栈段描述符(32位段,DPL = 2,RPL = 2)
 64     DemoStack2     DESCRIPTOR<DemoStack2Len - 1,DemoStack2Seg,,ATDW + D32 + DPL2,>
 65     DemoStack2_Sel = (DemoStack2 - DemoLDT) + TIL + RPL2
 66
 67     ;演示任务代码段描述符(32位段,DPL = 2,RPL = 2)
 68     DemoCode     DESCRIPTOR<DemoCodeLen - 1,DemoCodeSeg,,ATCE + D32 + DPL2,>
 69     DemoCode_Sel = (DemoCode - DemoLDT) + TIL + RPL2
 70
 71     ;演示任务数据段描述符(32位段,DPL = 3,RPL = 0)
 72     DemoData     DESCRIPTOR<DemoDataLen - 1,DemoDataSeg,,ATDW + D32 + DPL3,>
 73     DemoData_Sel = (DemoData - DemoLDT) + TIL
 74
 75     ;把演示任务LDT作为普通数据段描述的描述符(16位段,DPL = 2,RPL = 0)
 76     ToDLDT     DESCRIPTOR<DemoLDTLen - 1,DemoLDTSeg,,ATDW + DPL2,>
 77     ToDLDT_Sel = (ToDLDT - DemoLDT) + TIL
 78
 79     ;把临时任务TSS作为普通数据段描述的描述符(16位段,DPL = 2,RPL = 0)
 80     ToTTSS     DESCRIPTOR<TempTSSLen - 1,TempTSSSeg,,ATDW + DPL2,>
 81     ToTTSS_Sel = (ToTTSS - DemoLDT) + TIL
 82
 83     ;LDT含非门描述符个数
 84     DemoLDTNum = ($ - DemoLDT)/(size DESCRIPTOR)
 85
 86     ;指向子程序SubRB的调用门(DPL = 3,RPL = 2)
 87     ToSubR     GATE<low offset SubRB,SubR_Sel,0,AT386CGAT + DPL3,0>
 88     ToSubR_Sel = (ToSubR - DemoLDT) + TIL + RPL2
 89
 90     ;指向临时任务Temp的任务门(DPL = 3,RPL = 0)
 91     ToTempT     GATE<0,TempTSS_Sel,0,ATTASKGAT + DPL3,0>
 92     ToTempT_Sel = (ToTempT - DemoLDT) + TIL
 93
 94     ;LDT字节长度
 95     DemoLDTLen = $ - DemoLDT
 96 DemoLDTSeg    ends
 97
 98
 99 ;------------------------------------------
100 ;演示任务任务状态段(TSS)
101 DemoTSSSeg    segment    para    use16
102     DTSS    TASKSS<>
103             db    0ffh                    ;IO许可位结束标志
104     DemoTSSLen = $ - DemoTSSSeg
105 DemoTSSSeg    ends
106
107
108 ;------------------------------------------
109 ;临时任务的任务状态段(TSS)
110 TempTSSSeg    segment    para    use16
111     TempTask    TASKSS<>
112                 db    0ffh
113     TempTSSLen = $ - TempTSSSeg
114 TempTSSSeg    ends
115
116 ;------------------------------------------
117 ;演示任务0级堆栈段(32位段)
118 DemoStack0Seg    segment    para    use32
119     DemoStack0Len = 1024
120     db    DemoStack0Len dup(0)
121 DemoStack0Seg    ends
122
123
124 ;------------------------------------------
125 ;演示任务2级堆栈段(32位段)
126 DemoStack2Seg    segment    para    use32
127     DemoStack2Len = 512
128     db    DemoStack2Len dup(0)
129 DemoStack2Seg    ends
130
131 ;------------------------------------------
132 ;演示任务数据段(32位段)
133 DemoDataSeg    segment    para    use32
134     message        db    ‘Value = ‘,0
135     DemoDataLen = $ - DemoDataSeg
136 DemoDataSeg    ends
137
138 ;------------------------------------------
139 ;子程序代码段(32位段)
140 SubRSeg    segment    para    use32
141     assume    cs:SubRSeg
142 ;从堆栈中取出参数显示
143 SubRB    proc    far
144     push       ebp
145     mov        ebp,esp
146     pushad
147     ;从堆栈(0级)中取提示信息串偏移
148     mov        eax,[ebp + 12]
149     mov        esi,eax
150     mov        ah,7
151     jmp        short SubR2
152 SubR1:
153     stosw
154 SubR2:
155     lodsb
156     or         al,al
157     jnz        SubR1
158     ;从堆栈(0级)中取显示值
159     mov        edx,[ebp + 16]
160     mov        ecx,8
161 SubR3:
162     rol        edx,4
163     mov        al,dl
164     call       HTOASC
165     stosw
166     loop       SubR3
167     popad
168     pop        ebp
169     ret        8
170 SubRB    endp
171
172 HTOASC    proc
173     and        al,0fh
174     add        al,90h
175     daa
176     adc        al,40h
177     daa
178     ret
179 HTOASC endp
180
181     SubRLen = $ - SubRSeg
182
183 SubRSeg    ends
184
185 ;------------------------------------------
186 ;演示任务的代码段(32位段)
187 DemoCodeSeg    segment    para    use32
188     assume    cs:DemoCodeSeg
189 DemoBegin:
190     ;把要复制的参数个数置入调用门
191     mov        fs:ToSubR.Dcount,2
192     ;向堆栈(2级)中压入参数
193     mov        dword ptr gs:TempTask.TREIP,offset ToReal
194     push       dword ptr gs:TempTask.TREIP
195     push       offset message
196     ;通过调用门调用子程序SubRB
197     CALL32     ToSubR_Sel,0
198     ;把指向规范数据段描述符的选择子填入临时任务TSS
199     assume     ds:TempTSSSeg
200     push       gs
201     pop        ds
202     mov        ax,Normal_Sel
203     mov        TempTask.TRDS,ax
204     mov        TempTask.TRES,ax
205     mov        TempTask.TRFS,ax
206     mov        TempTask.TRGS,ax
207     mov        TempTask.TRSS,ax
208     ;通过任务切换到临时任务
209     JUMP32     ToTempT_Sel,0
210     DemoCodeLen = $ - DemoCodeSeg
211 DemoCodeSeg    ends
212
213 ;------------------------------------------
214 ;临时代码段(16位段,0级)
215 TempCodeSeg    segment    para    use16
216     assume    cs:TempCodeSeg
217 Virtual:
218     ;装载TR
219     mov        bx,TempTSS_Sel
220     ltr        bx
221     ;直接切换到演示任务
222     ;JUMP16    ToDemoT_Sel,0
223     JUMP16     DemoTSS_Sel,0
224 ToReal:
225     ;准备切换回实模式
226     clts    ;清任务切换标志
227     ;
228     mov        eax,cr0
229     and        ax,0fffeh
230     mov        cr0,eax
231     JUMP16     <seg Real>,<offset Real>
232     TempCodeLen = $ - TempCodeSeg
233 TempCodeSeg    ends
234
235
236 ;------------------------------------------
237 ;实模式下的数据段
238 RDataSeg    segment    para    use16
239     VGDTR    PDESC<GDTLen - 1,>
240     SPVAR    dw    ?
241     SSVAR    dw    ?
242 RDataSeg    ends
243 ;------------------------------------------
244 ;实模式下的代码段
245 RCodeSeg    segment    para    use16
246     assume    cs:RCodeSeg,ds:RDataSeg,es:RDataSeg
247 start:
248     mov        ax,RDataSeg
249     mov        ds,ax
250     cld
251     ;初始化GDT
252     call       INIT_GDT
253     ;初始化演示任务LDT
254     mov        ax,DemoLDTSeg
255     mov        fs,ax
256     mov        si,offset DemoLDT
257     mov        cx,DemoLDTNum
258     call       INIT_LDT
259     ;初始化TSS
260     call       INIT_TSS
261     ;实模式堆栈保护
262     mov        SSVAR,ss
263     mov        SPVAR,sp
264     ;装载GDTR和切换到保护模式
265     lgdt       fword ptr VGDTR
266     cli
267     mov        eax,cr0
268     or         eax,1
269     mov        cr0,eax
270     JUMP16     TempCode_Sel,<offset Virtual>
271 Real:
272     ;又回到实模式
273     mov        ax,RDataSeg
274     mov        ds,ax
275     lss        sp,dword ptr SPVAR
276     sti
277     mov        ax,0700h
278     int        21h
279     mov        ax,4c00h
280     int        21h
281 ;------------------------------------------
282 ;初始化全局描述符表的子程序
283 ;(1)把定义时预置的段值转换成32位段基地址并置入描述符内相应字段
284 ;(2)初始化为GDTR准备的伪描述符
285 INIT_GDT    proc    near
286     push    ds
287     mov        ax,GDTSeg
288     mov        ds,ax
289     mov        cx,GDTNum                     ;初始化描述符的个数
290     mov        si,offset EFFGDT              ;开始偏移
291     assume     si:ptr DESCRIPTOR
292 INITG:
293     mov        ax,[si].BaseL                  ;取出预置的段值
294     movzx      eax,ax                         ;扩展到32位
295     shl        eax,4
296     shld       edx,eax,16                     ;分解到2个16位寄存器
297     mov        [si].BaseL,ax                  ;置入描述符相应字段
298     mov        [si].BaseM,dl
299     mov        [si].BaseH,dh
300     add        si,size DESCRIPTOR             ;调整到下一个描述符
301     loop       INITG
302     assume     si:nothing
303     pop        ds
304     ;
305     mov        bx,16                          ;初始化为GDTR准备的伪描述符
306     mov        ax,GDTSeg
307     mul        bx
308     mov        word ptr VGDTR.Base,ax
309     mov        word ptr VGDTR.Base + 2,dx
310     ret
311 INIT_GDT endp
312 ;------------------------------------------
313 ;初始化演示任务局部描述符表的子程序
314 ;把定义时预置的段值转换成32位段基地址并置入描述符内的相应字段
315 ;入口参数:FS:SI = 第一个要初始化的描述符
316 ;           CX = 要初始化的描述符个数
317 INIT_LDT    proc
318     assume    si:ptr DESCRIPTOR
319 ILDT:
320     mov        ax,fs:[si].BaseL
321     movzx      eax,ax
322     shl        eax,4
323     shld       edx,eax,16
324     mov        fs:[si].BaseL,ax
325     mov        fs:[si].BaseM,dl
326     mov        fs:[si].BaseH,dh
327     add        si,size DESCRIPTOR
328     loop       ILDT
329     assume     si:nothing
330     ret
331 INIT_LDT endp
332 ;------------------------------------------
333 ;初始化TSS段子程序
334 INIT_TSS    proc
335     mov        ax,DemoTSSSeg
336     mov        fs,ax
337     mov        si,offset DTSS
338     assume     si:ptr TASKSS
339     mov        fs:[si].TRLink,0                ;链接字 = 0
340     mov        fs:[si].TRESP0,DemoStack0Len    ;0级堆栈指针
341     mov        fs:[si].TRSS0,DemoStack0_Sel
342     mov        fs:[si].TRESP2,DemoStack2Len    ;2级堆栈指针
343     mov        fs:[si].TRSS2,DemoStack2_Sel
344     mov        fs:[si].TRESP,DemoStack2Len     ;当前使用2级堆栈
345     mov        fs:[si].TRSS,DemoStack2_Sel
346     mov        fs:[si].TRCR3,0                 ;CR3 = 0
347     mov        fs:[si].TREDI,0b8000h           ;ES:EDI指向视频输出缓冲区
348     mov        fs:[si].TRES,Video_Sel
349     mov        fs:[si].TREIP,offset DemoBegin  ;CS:EIP指向演示代码段起始位置
350     mov        fs:[si].TRCS,DemoCode_Sel
351     mov        fs:[si].TRDS,DemoData_Sel       ;DS指向演示任务数据段
352     mov        fs:[si].TRFS,ToDLDT_Sel         ;FS指向演示任务LDT(被当成数据段)
353     mov        fs:[si].TRGS,ToTTSS_Sel         ;GS指向临时任务TSS(被当成数据段)
354     mov        fs:[si].TRLDT,DemoLDT_Sel       ;演示任务LDTR
355     assume     si:nothing
356     ret
357 INIT_TSS endp
358 RCodeSeg    ends
359     end        start    

3、  源代码说明

  依然存在的一些类似问题,要么直接copy这里的代码,要么对比原书去找它们了,不重要。须注意的是在引用结构的时候这里采用了一种新的形式。

4、  输出

5、  测试说明

  1)  从Temp任务直接通过TSS切换到Dome任务

    LTR指令装载Temp任务的TSS并刷新高速缓冲区,以指示当前任务。Temp任务采用段间JMP指令进行任务切换:CPL = DPL = 0且目标TSS指示的是一个可用任务。这里有个很纠结的地方,切换任务以后,Temp任务的现场的确被保存了,只不过EIP寄存器都被初始化为0,导致系统奔溃:

    而且输出如下:

    从输出来看,EIP的确被初始化为0了,为什么是没有保存现场而是被初始化为0呢?因为我在JMP前强行给EIP赋值过,测试发现输出还是0。我测试自己电脑的CPU是686,不知道是不是CPU对JMP切换任务已经更换了策略,还是说有什么潜在的问题没有发现,暂时不得而知,总之,我尝试了各种方法,包括使用任务门、修改Temp的TSS任务为忙的TSS,这些尝试都是导致的系统直接奔溃。

  2)  从Dome任务通过任务门切换到Temp任务

    采用段间JMP,通过任务门切换回Temp任务:source.CPL(=2)<=gate.DPL(=3)且source.RPL(=0)<=gate.RPL(=0)所以成功进入任务门。进入门以后不再对权限等级进行保护检测(可以切换到目标任务的任何权限等级),由于目标任务可用,则直接实行了切换。由于上述毛病的存在,我这这里强势设置了一下EIP,使用的语句是“mov  dword ptr gs:TempTask.TREIP,offset ToReal”。

  3)  演示任务内特权级变换和堆栈传递参数

    采用段间CALL,通过调用门“ToSunR”调用子程序SubR。由于有权限等级的切换,栈也进行了切换。首先压入参数,须注意,压入时须保证CPL<=DPL且RPL<=DPL,栈是一种存储描述符。同时,注意调用门中Dcount字段,这个字段是压入参数的双字数目,这里压入了2个双字,所以设置为2。进入门的保护检测不再赘述。执行子程序时注意堆栈平衡。其它的没什么好说的。

  4)  别名技术

    在为了把调用门“ToSunR”中的Dcount字段设置为2时,使用了数据段描述符“ToDLDT”描述门所在演示任务的LDT段;此外在修改Temp任务的TSS时,也将其视普通的数据段。对同一内存段使用不同的解释方式,就是别名技术,这个不见得多么高深。

时间: 2024-11-10 13:32:17

《80X86汇编语言程序设计教程》十五 任务切换实例的相关文章

《80X86汇编语言程序设计教程》二十四 进入与离开V86模式实例

1.  这是我这本书调得最失败的一个实例,而且问题都是超出了这本书能教会我的范畴.作者对调试环境几乎只字不提,这让我有点费解.原作者使用TASM的编译代码,而我使用的MASM加虚拟机进行测试,不知道这两样东西哪里有问题还是源代码要做哪些修正.理论知识参考"<80X86汇编语言程序设计教程>二十二 分页管理机制与虚拟8086模式". 2.  进入和离开V86模式实例:各2种方式进入和离开V86模式.V86模式下8086程序调用实模式软中断处理程序.逻辑功能:以驻留方式结束程序

《80X86汇编语言程序设计教程》二十五 结语(读后感:这本书怎么样)

这本书的推荐星级是:5星.毕竟是经典书籍,没什么好说的. 就汇编本身而言,在编写高效率程序以及对程序的优化,调试,工程的逆向都是一门基础:就理论上的操作系统而言,汇编让你了解CPU,了解计算机的体系结构,它是阅读操作系统源码的前提,这也是<80X86汇编语言程序设计教程>做得比较好的一点,它对386的保护方式下的编程写得比较详实,读完整本书,会发现这学的不仅仅是汇编语言,还有CPU的体系架构,它让你基本猜测得到在编写基于80386CPU的操作系统时,大概要做一些什么事情. 阅读前,我选过几本书

《80X86汇编语言程序设计教程》十 实模式与保护模式的切换实例

1.  再次声明,需要纯DOS系统才能看到满意测试效果.内容是演示实模式与保护模式切换实例,实现功能是16进制显示从110000H开始的256个字节的值 2.  源代码如下: 1 ;功能:演示实模式与保护模式的切换,16进制显示从110000H开始的256个字节的值 2 ;16位偏移的段间直接转移指令的宏定义,这是一个JMP指令到所描述的地址 3 4 JUMP macro selector,offsetv 5 db 0eah ;操作码 6 dw offsetv ;16位偏移 7 dw selec

《80X86汇编语言程序设计教程》十九 操作系统类指令与输入输出保护

1.  通常只在操作系统代码中使用,80386支持4个特权等级,操作系统指令也可分3种:实模式和任何特权级下可执行指令.实模式及特权级0下可执行的指令和仅在保护模式下执行的指令. 1)  实模式和任何特权级下可执行的指令 a)存储全局和中断描述符表寄存器指令 GDT与IDT整个系统各只有一张,它们的定位信息分别保存在GDTR与IDTR中,这两个寄存器的值可以被保存.须注意,LDT表示任务私有,存储LDTR值的指令不属于这一类. i)存储全局描述符表寄存器指令:SGDT  DST DST是48位(

《80X86汇编语言程序设计教程》十一 32位代码段和16位代码段切换实例

1.  演示32位代码段与16位代码段之间的切换.实现的功能是以十六进制和ASCII码字符两种形式显示从内存地址100000H开始的16个字节的内容. 2.  源代码如下: 1 ;DosTest.Asm 2 ;16位偏移的段间转移指令的宏定义 3 ;使用于16位段,用于跳转到32位目的段 4 ;注意:标号偏移必须在16位二进制符号数数能表示的范围之内 5 JUMP16 macro selector,offsetv 6 db 0eah ;操作码 7 dw offsetv ;16位偏移 8 dw s

《80X86汇编语言程序设计教程》二十三 分页管理机制实例

1.  理论知识参考"<80X86汇编语言程序设计教程>二十二 分页管理机制与虚拟8086模式".演示分页机制实例:初始化页目录表和部分页表:启用分页管理机制:关闭分页管理机制等.逻辑功能:在屏幕上显示一条表示已启用分页管理机制的提示信息.大体步骤是:在实模式下拷贝显示串程序的代码到预定义区域,转保护模式,初始化页目录和2个页表,开启分页机制,转入预定义区执行显示代码,然后关闭分页机制,重新回到实模式,程序终止. 2.  源代码 "386scd.asm"

《80x86汇编语言程序设计》保护模式第一个例题

<80x86汇编语言程序设计>保护模式第一个例题的一些个人理解和注释 ; 16位偏移的段间直接转移指令的宏定义 02.jump macro selector, offsetv 03. 04. db 0eah ; jmp far 的操作码 05. dw offsetv 06. dw selector 07. 08.endm 09. 10.; 字符显示宏指令定义 11.echoch macro ascii 12. 13. mov ah, 2 14. mov dl, ascii 15. int 21

无废话ExtJs 入门教程十五[员工信息表Demo:AddUser]

无废话ExtJs 入门教程十五[员工信息表Demo:AddUser] extjs技术交流,欢迎加群(201926085) 前面我们共介绍过10种表单组件,这些组件是我们在开发过程中最经常用到的,所以一定要用到非常熟练才可以,今天我们会通过一个员工信息表实例,再把这些组件串一下. (1)TextField  (2)Botton  (3)NumberField (4)Hidden (5)DataFiedl (6)RadioGroup (7)CheckBoxGroup (8)Combobox (9)F

RabbitMQ入门教程(十五):普通集群和镜像集群

原文:RabbitMQ入门教程(十五):普通集群和镜像集群 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/vbirdbest/article/details/78740346 分享一个朋友的人工智能教程(请以"右键"->"在新标签页中打开连接"的方式访问).比较通俗易懂,风趣幽默,感兴趣的朋友可以去看看. 普通集群 推荐一篇优秀的文章: RabbitM