注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

编程学习

我的网上家园

 
 
 

日志

 
 

15章习题一: 两种修改方案  

2013-04-24 15:27:29|  分类: 《x86汇编语言: |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
15章习题一:
1. 修改本章的源程序,使之能够顺序完成以下工作:
    ①从程序管理器任务切换到任务A,显示消息后返回程序管理器;
    ②从程序管理器任务切换到任务B,显示消息后返回程序管理器;
    ③再从程序管理器任务切换到任务A,显示另一条消息,然后返回程序管理器;
    ④再从程序管理器任务切换到任务B,显示另一条消息,再返回程序管理器.
  
题目分析:
在书中的源代码,1,2已经实现了,我们只需要修改一下实现3,4即可.

我们先来分析一下书中的源代码,任务A是如何返回到程序管理器的:

任务A通过调用门调用公共例程段的例程进入0特权级代码执行.

任务A(用户程序)通过调用门调用 [fs:TerminateProgram] 例程时,
进入0特权级的代码,此时CS指向内核的公共例程段,EIP指向内核的公共例程:
terminate_current_task,在该例程通过使用 iretd 指令返回到 程序管理器任务时,
保存到任务A(用户程序)TSS中的CS值是内核公共例程段的选择子,EIP指向例程
terminate_current_task结束指令的下一条指令,也就是iretd指令后面的偏移.

基于上面的分析,如果任务管理器要再次切换到任务A,则会从内核公共例程段
的terminate_current_task  在返回到程序管理器任务之前的下一条指令(也就是iretd)
后面的指令继续执行,可是这条指令的后面是内核数据段了,不可能返回到任务A
去执行,那么该如何修改呢?


解决方案有两种:

一种是修改用户程序,使用iretd指令返回到任务管理器,不通过调用公共例程段的
例程来返回到任务管理器,这样以来,因为修改了返回到程序管理器的方法,程序管
理器在加载任务B时也不能用jmp far 的方式来切换到任务B了,只能用call far方
式,因为用户程序使用iretd方式进行返回,这样程序管理器任务就可以再次切换到
任务A去执行了.


另一种修改方案是: 在公共例程段的iretd指令后面加一条指令 retf 以返回到任
务A,同时需要注意,公共例程terminate_current_task改变了DS的值,所以我们修改
一下,在改变之前保存DS的原值,在返回之前恢复DS的值.

  
修改方法一:
--------------------------------------------------------------------------------    
用户程序的修改:
===============================================================================
分析: 要想让任务管理器能够再次切换到用户任务,用户任务在返回到任务管理器任务时,
应该使用 iretd 指令.

在 call far [fs:TerminateProgram] 语句之前添加以下语句:

      iretd
 mov ebx,message_3
 call far [fs:PrintString] ;显示消息
 
因为不再需要切换到任务A,在最后可以使用 call far [fs:TerminateProgram] 返回到程序
管理器.
 
在数据段添加以下字符串定义:
message_3 db  0xd,0xa,'User Task: Hi! nice to meet you too.',0xd,0xa,0 
===============================================================================

内核修改:
===============================================================================
内核数据段增加两个字符串定义(当然,这不是必须的),以表示任务管理器重新切换到用户任务.

prgman_msg4 db 0xd,0xa,'[PROGRAM MANAGER]:I am return to user task A.',0
prgman_msg5 db 0xd,0xa,'[PROGRAM MANAGER]:I am return to user task B.',0

在内核代码段,mov ebx,prgman_msg3 之前添加以下代码:

mov ebx,prgman_msg4
call sys_routine_seg_sel:put_string  ;显示程序管理器将再次切换到任务A
mov eax,[tcb_chain]                  ;取得第一个任务的TCB
call far [es:eax+0x14]               ;再次切换到任务A,可以使用jmp far 方式.
mov ebx,prgman_msg5                  
call sys_routine_seg_sel:put_string  ;显示程序管理器将再次切换到任务B
mov eax,[es:eax]                     ;取得第二个任务的TCB
jmp far [es:eax+0x14]                ;再次切换到任务B,可以使用jmp far 方式.
 
把原来 jmp far [es:ecx+0x14] 用于加载任务B的代码改为 call far [es:ecx+0x14].


修改方法二:
----------------------------------------------------------------------------------
内核公共例程段:
==========================================================================
在 mov eax,core_data_seg_sel 语句之前加一条指令: push ds
在 jmp far [prgman_tss] 语句与 iretd 语句后面各加以下两条指令: 
pop ds ;恢复DS的原值
retf   ;返回到3特权级的用户任务.

内核代码段:
==========================================================================
在 jmp far [es:ecx+0x14] 后面之后添加以下指令:

     mov ebx,prgman_msg4
call sys_routine_seg_sel:put_string  
mov eax,[tcb_chain]
call far [es:eax+0x14]  
mov ebx,prgman_msg5
call sys_routine_seg_sel:put_string
mov eax,[es:eax]
call far [es:eax+0x14]
 
内核数据段:  
==========================================================================
在内核数据段添加以下字符串定义:

prgman_msg4  db 0xd,0xa,'[PROGRAM MANAGER]:I am return to user task A.',0xd,0xa,0  
prgman_msg5  db 0xd,0xa,'[PROGRAM MANAGER]:I am return to user task B.',0xd,0xa,0
用户程序修改:
==========================================================================

代码段:
在 call far [fs:TerminateProgram] 后面添加以下指令:
 
mov ebx,message_3
call far [fs:PrintString]
call far [fs:TerminateProgram]
 
在数据段添加以下字符串定义:
 
message_3  db  0xd,0xa,' User Task: Hi! nice to meet you too.',0xd,0xa,0 

  评论这张
 
阅读(38)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017