汇编网首页登录博客注册
taotling的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
  •  有许多事,让DEBUG洗过更明白; 天真如我,学习汇编,以为撑得住未来; 而谁担保芯永远不会染上尘埃...
  • 『姓名』:TAOT                
  • 『性别』:保密  『发送消息
  • 个人说明:
  • 详细信息『加为好友』
学习动态
好友圈
文章收藏
友情链接

[2008-03-30 19:50] 推荐博文 是否可以在自己写的INT 0H中断例程结束处用IRET来返回调用程序

提出问题者:wesom
地址:http://www.asmedu.net/bbs/pasteinfo.jsp?part=1&level=book&kind=1013&qkSg=2&qID=13334


问题:
===============================
书上的例子使用的是调用另外的中断mov ax,4c00h int 21h来退出,如果用iret来出栈为什么不能退出呢? 
溢出程序: 
code segment 
   begin : mov ax,data 
           mov ds,ax 
           mov ax,1000h 
           mov bh,1 
           div bh 
           mov ax,4c00h 
           int 21h 
code ends 
已安装的中断如下: 
do0:  
             jmp short dostart 
             db "overflow!"     
dostart: 
          ;设置ds:si指向字符串 
          mov ax,cs 
          mov ds,ax 
          mov si,202h 
             mov ax,0b800h 
             mov es,ax 
             mov di,12*160 + 36*2 
             mov cx,9 
             s:mov al,[si] 
             mov es:[di],al 
             inc si 
             add di,2 
             loop s 
             mov ax,4c00h 
             int 21h 
                
  doend:  
          nop 
将mov ax,4c00h 
  int 21h 
改为iret为什么不行呢?
============================






分析:
=============================

首先看看安装中断例程的代码: 
===============SETUP CODE======================= 
assume cs:codesg 

codesg segment 
  start: 
     mov ax,cs 
     mov ds,ax 
     mov si,offset do0 

     mov ax,0000H 
     mov es,ax 
     mov di,0200H 

     mov cx,offset do0End-offset do0 
     cld 
     rep movsb 

     mov word ptr es:[0],0200H 
     mov word ptr es:[2],0000H 

     mov ax,4C00H 
     int 21H 

do0: 
    jmp short do0Start 
    db 'Divide Error!' 
do0Start: 
        mov ax,cs 
        mov ds,ax 
        mov si,0202H 
  
 mov ax,0B800H 
 mov es,ax 
 mov di,12*160+34*2 

 mov cx,13 
 PutToDisplayRom: 
     mov ah,01000001B 
     mov al,ds:[si] 
     mov es:[di],ax 
     inc si 
     add di,2 
 loop PutToDisplayRom 
  

;注意从此处开始是另外加入的为记录栈中IP、CS的代码。 
;可先跳过。 
  mov bx,5000H           
  mov ds,bx              
  mov si,0 

  mov bp,sp 
  mov ax,ss:[bp] 
  mov ds:[0],ax 
   
  mov ax,ss:[bp+2] 
  mov ds:[2],ax 

  mov ax,ss:[bp+4] 
  mov ds:[4],ax 

 ;mov ax,4C00H       ;不调用INT 21H结束程序。 
 ;int 21H 
  


                     ;这里为什么要这么做先不用管,看到后面就明白。 
 mov ax,ss:[bp]      ;把栈中的调用中断程序时压入的IP传给AX 
 add ax,2            ;修改AX为引发中断的指令的下一条指令的IP 
 mov ss:[bp],ax      ;将栈中的调用中断程序时压入的IP修改为引发中断的下一条指令的IP 
 IRET                ;用IRET返回调用中断的程序。 
                     
do0End:nop 

codesg ends 
end start 
========================================================== 

根据tomato兄弟的提示, 
我们需要来确定一下到底系统调用INT 0的时候是否记录了IP、CS。 

此时我们应该在脑海中有个映像,即系统引发INT 0中断进入中断例程时, 
如果不出现意外的话,栈的内容应该为: 
[IP]    [CS]       [Flag REG] 
[栈顶]  [栈顶+2]   [栈顶+4] 


因此,我们可以在自己的中断例程中加入以下代码来将进行INT 0中断后 
栈中所记录的IP、CS到底是什么: 
  mov bx,5000H   ;用5000:0000H来开始记录栈中的内容 
  mov ds,bx 
  mov si,0 

  mov bp,sp       ;用BP代替SP来访问栈中内容 
  mov ax,ss:[bp]  ;将栈顶值传入AX,这个值应该是系统在调用INT 0后压入的 
  mov ds:[0],ax   ;将AX值,也就是将栈顶的值传入5000:0000H 
   
  mov ax,ss:[bp+2] 
  mov ds:[2],ax    ;同理,将(栈顶+2)的值即CS传入5000:0002H 

  mov ax,ss:[bp+4] 
  mov ds:[4],ax    ;同理,将(栈顶+4)的值即 Flag REG传入5000:0004H 


其次,我们来看看测试代码: 
==================TEST CODE============================== 
assume cs:codesg 

codesg segment 
start: 
    mov ax,0FFFFH 
    mov dx,0FFFFH 
    mov bx,1 
    div bx 

    mov cx,9999H 
    mov bx,8888H 

    mov ax,4c00H 
    INT 21H 

codesg ends 
end start 
========================================================= 

我们将SETUP CODE编译连接后运行。 
再将TEST CODE编译连接后用DEBUG 进入调试: 

TEST CODE代码进入DEBUG后的相应机器码: 
G:\Code\new>debug test04.exe 
-u 
0CCE:0000 B8FFFF        MOV     AX,FFFF 
0CCE:0003 BAFFFF        MOV     DX,FFFF 
0CCE:0006 BB0100        MOV     BX,0001 
0CCE:0009 F7F3          DIV     BX            ;注意这里的IP为0009H 
0CCE:000B B99999        MOV     CX,9999 
0CCE:000E BB8888        MOV     BX,8888 
0CCE:0011 B8004C        MOV     AX,4C00 
0CCE:0014 CD21          INT     21 
0CCE:0016 2AED          SUB     CH,CH 
0CCE:0018 81E15F00      AND     CX,005F 
0CCE:001C 2BC1          SUB     AX,CX 
0CCE:001E 8946E8        MOV     [BP-18],AX 

==============下面开始用t单步进行============= 
-t 

AX=FFFF  BX=0000  CX=0016  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000 
DS=0CBE  ES=0CBE  SS=0CCE  CS=0CCE  IP=0003   NV UP EI PL NZ NA PO NC 
0CCE:0003 BAFFFF        MOV     DX,FFFF 
-t 

AX=FFFF  BX=0000  CX=0016  DX=FFFF  SP=0000  BP=0000  SI=0000  DI=0000 
DS=0CBE  ES=0CBE  SS=0CCE  CS=0CCE  IP=0006   NV UP EI PL NZ NA PO NC 
0CCE:0006 BB0100        MOV     BX,0001 
-t 

AX=FFFF  BX=0001  CX=0016  DX=FFFF  SP=0000  BP=0000  SI=0000  DI=0000 
DS=0CBE  ES=0CBE  SS=0CCE  CS=0CCE  IP=0009   NV UP EI PL NZ NA PO NC 
0CCE:0009 F7F3          DIV     BX 
-t 

AX=000B  BX=5000  CX=9999  DX=FFFF  SP=0000  BP=FFFA  SI=0000  DI=07DE 
DS=5000  ES=B800  SS=0CCE  CS=0CCE  IP=000E   NV UP EI PL NZ NA PO NC 
0CCE:000E BB8888        MOV     BX,8888 

到了这里,应该注意IP为000BH处的指令MOV CX,9999H已被执行, 
因为我们看到(CX)=9999H了。 



到这里我们发现,在做了INT 0中断处理后,成功返回主程序, 
也就是可以用IRET作中断返回。 

但事情到这步没结束, 
我们看看被记录入5000:0000H和5000:0002H处的IP、CS分别是什么? 
-d 5000:0 f 
5000:0000  09 00 CE 0C 02 33 B8 FF-00 00 00 00 00 00 00 00 

注意5000:0000H处的IP值是09H。结合上面的0CCE:0009H处的指令看看,有问题了吗???? 

引发中断时,被压栈的IP应该是引发中断处指令的下一条指令的IP才对啊? 
为什么这里IP为0009H处的 DIV BX 指令引发了INT 0后,被压入栈的IP还是0009H呢? 
应该是000BH才对吧。 

或许这就是INT 0H中断被引发后的特殊之处, 
它压栈的IP就是引发INT 0H处指令的IP,而不是其后一条指令的IP。 
那是不是所有内部中断所压栈的IP都不是引发其中断后的指令的IP呢? 
这个大家可以自己去试一下其他内部中断被调用时的情况, 
我试了一下INT 04H引发后压栈的同样是引发这个中断时指令的IP, 
而不是引发它的指令的下一条指令的IP。 

这就是为什么要在SETUP CODE安装程序中IRET前写入下面的指令: 
 mov ax,ss:[bp] 
 add ax,2       
 mov ss:[bp],ax    
对返回调用中断程序的IP(在栈中)进行修改的原因。 

另外我们还看到,在测试程序中, 
当用t命令单步跟踪后,从IP为0009H处的指令DIV BX引发INT 0H执行完返回后, 
其下一条指令并没有响应单步t就被执行了, 
也就是IP为000BH处的指令MOV CX,9999H并没有响应单步中断就已被执行了。 

所以,如果我们不在自己写的中断例程中修改栈中的返回IP值, 
直接用IRET其实是返回了的,但是返回后执行的仍然是0009H这条指令, 
从而形成了死循环,表面上就是不能用IRET返回调用中断的程序了。 

最后结论是,INT 0H可以用IRET返回,不过对于其压栈的IP的特殊情况, 
要做一下处理。
评论次数(29)  |  浏览次数(3520)  |  类型(值得看看的问题) |  收藏此文  | 

[  tomato   发表于  2008-03-31 10:59  ]

看到博主的回帖了,是啊,原来内中断不能返回的真正原因是因为栈的保存是除法的那条指令的偏移地址,恢复现场的时候还会继续执行除法指令,出现死循环所致。
博主厉害,很有发展潜力,博主加油!

[  taotling   发表于  2008-03-31 12:16  ]

可是还有两个遗留问题:
其一:
    为什么INT 0H中断执行完返回后,
    其IP还指向引发这个中断的指令的IP?

或者这样表达也行:
    当某些内中断被引发后,为什么被压进行压栈的IP
   是引发这个内中断的指令的IP,却不是引发这个内中断
   的指令的下一条指令的IP?


我想了想,觉得应该是:
如果这样的中断被引发,
也就是程序的相关指令肯定操作出了问题,
所以,应该将IP指向出问题的指令的地方,
而不应该继续再执行下去。
也就是说:

“既然已经错了,就不要错下去了,打住吧!”

也许秉着这个精神,所以引发某些内中断时,
压栈IP为引发中断处指令的IP吧。


其二:
为什么用IRET从内中断INT 0H的中断例程中返回后,
引发这个内中断的指令的下一个指令不响应单步就被执行了呢?

其实应理解为:
    从内中断INT 0H的中断例程返回后,
    CPU不响应单步中断就把引发INT 0H的指令执行了。
这样的理解就对了。


我们看到的结果是不响应单步,CPU执行了引发INT 0H的指令的下一条指令,但是这个结果是因为我们在中断例程中将IP值改变后的结果。想想,如果我们不在中断例程中改变栈中的返回IP值,那么,CPU在中断例程返回后,就应该是不响应单步中断而去执行引发中断的指令本身,而不是这条指令的下一条指令了。

我觉得这样的处理方式有一种思想在里面:
就按常理来说,能够引起这些中断的指令,都是有问题的,
也就是含有这条指令的应用程序有问题,要被终止,
所以可以推断INT 0H的原中断例程中肯定是用类似
MOV AX,4C00HINT 21H这样的指令来结束原应用程序的运行,然后返回装载应用程序的装载器下;

但现在我们改了INT 0H的中断例程,要使中断例程执行完后,不结束应用程序,而是返回调用中断的应用程序,CPU根据这种中断的特殊性,会在返回后回到断点处继续执行断点处的指令,也就是将引发中断的指令再执行一次,如果没问题了就往下,如果还是又引发这个中断,那就是问题继续存在,那就这样做循环的动作吧,除非没问题了。

目前只能这么想了,感觉还是没把问题说清楚。

[  starrynight   发表于  2008-03-31 20:13  ]

中断处理程序有两种作用:
1、作为功能调用提供给程序员,作为汇编语言的API;
2、在程序运行过程中出现了异常,触发中断进行处理,处理有两种方式:
a、直接终止程序的执行,把CPU控制权交给加载程序;
b、对程序运行状态及相关环境进行相应更新,使得异常不影响后面的指令的执行。(可能还有别的方式,高手补充)

而这里所讨论的int 0中断,系统已经提供中断处理程序,采取的方式就是终止程序运行,正像博主所论证的那样不会再继续向下执行了。

然而,如果中断处理程序如果由我们自己来编写安装,测试的时候,那么,如果不考虑程序的实际逻辑功能,我们就可以有两种不同的思路了,可以返回,也可以稍加处理,继续执行后面的程序。

这是我的一点认识。

[  tomato   发表于  2008-03-31 21:08  ]

为什么用IRET从内中断INT 0H的中断例程中返回后, 
引发这个内中断的指令的下一个指令不响应单步就被执行了呢? 
------------------------
我的猜测:
当执行除法指令之前,先判断一下是否发生除法溢出,如果会发生除法溢出,则触发除法溢出中断程序,这条除法指令并没有执行,在我们的中断程序返回之前,修改了栈中的偏移地址的值,使它指向除法指令的下一条指令,相当于这条指令替换了触发中断但并没有执行的那条除法指令,当执行完这条指令之后才会触发单步中断。给我们的错觉却是没有触发单步中断却执行了指令,其实是我们没有执行指令所以没有触发中断,执行了一条指令才触发了中断,并没有多执行一条指令。

[  wesom   发表于  2008-04-01 18:06  ]

to taoling 
谢谢你的分析,不过我还是有些疑虑 
看了你的证明后,你的结论是:INT 0H可以用IRET返回,类似div的系统中断调用区别在于ip入栈时用的当前指令而非中断的下条指令,因此造成循环执行中断 
问题:使用debug的方式调试,遇到系统中断后会否做些别的动作,我的意思是当前栈的数据被改动,可能是debug程序的特定动作,假设当前指令是debug保存下来呢?(当然,是假设,我也不知道是否如此)如果是该情况的话,我对你上面的证明还是有疑惑的......

[  taotling   发表于  2008-04-01 22:28  ]

====to wesom===== 

这个问题好说:  
    如果你不用DEBUG来调试上面的TEST CODE测试程序,  
    你试试测试程序能否顺利执行完?  

    换句话说,如果栈里的IP是DEBUG压进去的,  
    那么,现在我们直接执行测试程序,  
    而不用DEBUG进行调试,  
    这样栈里的IP与DEBUG无关了吧,  
    测试程序执行,是能顺序执行结束返回的。  
    这说明IRET起了作用,  
    也说明INT 0H被引发后确实有压栈CS、IP  
    等动作,  
    要不IRET何来的IP、CS等,
    回到调用中断的测试程序,
    测试程序又如何能顺利结束?      

    也可以在中断例程里写一个显示程序,  
    把栈里的内容显示在屏幕上。  

    另外,如果你在IRET前加一个PUSH或POP的动作,  
    也就是改变SP值,  
    再安装运行一下测试程序,  
    因为IRET执行后的相关CS、IP有问题,  
    DOS虚模式下会出现NTVDM遇到一个硬错误的提示。  
    如果在DOS实模式下,出现这种错误,  
    电脑就提示让你重启。

[  starrynight   发表于  2008-04-02 12:20  ]

debug下div 执行过程:

t命令执行 置标识位TF=1

div指令执行---------------没有溢出,那就不用讨论了
 |
 |
 ---如果溢出引发溢出中断,

        中断过程 pushf 、置TF = 0

       中断过程其他步骤

        中断返回其他步骤 

        中断返回 popf 后,TF = 1

如果中断处理程序以iret方式返回原程序,那么不管当前CS:IP指向哪里,debug(系统)都认为t命令之前的指令根本还没有执行过,而如果当前CS:IP还指向溢出出错指令首地址,那么此位置处的有效指令还将获得执行,(正如前文说说,我们完全可以编写中断处理程序,更新这里的机器码),然后单步中断;如果当前CS:IP由于中断处理程序的处理而指向了下一条指令,就像博主所做的那样,当然也是要执行完此指令才能单步中断的。

至于中断过程中,push CS 和 push IP过程中系统是如何确定保存当前正在执行的指令的相应CS:IP,还是下一条的,我想,还可以在思考,在讨论。

[  taotling   发表于  2008-04-02 15:43  ]

======Quote form starrynigth======= 
至于中断过程中,push CS 和 push IP过程中系统是如何确定保存当前正在执行的指令的相应CS:IP,还是下一条的,我想,还可以在思考,在讨论。 

================================= 

我试了试,觉得如果是由一个指令(非中断调用指令)
引发一个中断,那么引发中断时压栈的时这个指令的IP,
如果是显示的用INT N来调用中断,那么引发中断时压栈的是INT N指令的一下条指令的IP。

[  游客   发表于  2008-04-02 17:48  ]

我们先不看入栈是当前指令还是下条指令,看看这个问题:
系统引发的除法溢出中断未何不能响应debug的t中断命令,同是中断,int n却可以响应?(debug不到下个指令...)

[  游客   发表于  2008-04-02 22:04  ]

div指令执行---------------没有溢出,那就不用讨论了 
 | 
 | 
 ---如果溢出引发溢出中断, 

        中断过程 pushf 、置TF = 0

[  游客   发表于  2008-04-02 22:05  ]

已经置0 还响应什么t中断----单步中断?~!!!!!

[  taotling   发表于  2008-04-02 22:56  ]

===Quote from 游客======
已经置0 还响应什么t中断----单步中断?~!!!!!
==========================================
是这样的:
t单步中断命令于INT 0H前执行;
INT 0H中断于-t命令后执行;
INT 0H中断例程返回,还原寄存器值(恢复IF,TF值);
t单步中断命令又可以得以执行。

你的疑问是这个意思吗?

[  taotling   发表于  2008-04-02 23:13  ]

===Quote from 游客====== 
我们先不看入栈是当前指令还是下条指令,看看这个问题: 
系统引发的除法溢出中断未何不能响应debug的t中断命令,同是中断,int n却可以响应?(debug不到下个指令...)

========================================== 

是啊,这是为什么呀?讨论讨论。


我今天在测试程序中用INT0H代替了DIV BX,
结果用DEUBG 装载调试时,用T能单步跟踪进自己写的INT 0H中断例程中。

如果测试程序中用DIV BX,当DIV BX引发INT 0H时,
t命令单步跟踪是进不了INT 0H中断例程的...

[  游客   发表于  2008-04-03 09:32  ]

to taotling:
你的疑问是这个意思吗?
-----------------------------------
我的“已经置0 还响应什么t中断----单步中断?~!!!!!”,并不是一个疑问句,我是在回答(反问)楼上的楼上的疑问,哈哈

[  wesom   发表于  2008-04-04 17:01  ]

楼上的楼上是me,除了单步进不去外,我还发现栈的内容不可信,每次debug一条指令后,其实栈里面的内容有保存当前指令的ip,当然栈顶sp是不会错的啦,还是有很多疑问...

[  taotling   发表于  2008-04-04 19:43  ]

上面的这个回贴你没看吧?
重复一次再:
====to wesom=====  

这个问题好说:   
    如果你不用DEBUG来调试上面的TEST CODE测试程序,   
    你试试测试程序能否顺利执行完?   

    换句话说,如果栈里的IP是DEBUG压进去的,   
    那么,现在我们直接执行测试程序,   
    而不用DEBUG进行调试,   
    这样栈里的IP与DEBUG无关了吧,   
    测试程序执行,是能顺序执行结束返回的。   
    这说明IRET起了作用,   
    也说明INT 0H被引发后确实有压栈CS、IP   
    等动作,   
    要不IRET何来的IP、CS等, 
    回到调用中断的测试程序, 
    测试程序又如何能顺利结束?       

    也可以在中断例程里写一个显示程序,   
    把栈里的内容显示在屏幕上。   

    另外,如果你在IRET前加一个PUSH或POP的动作,   
    也就是改变SP值,   
    再安装运行一下测试程序,   
    因为IRET执行后的相关CS、IP有问题,   
    DOS虚模式下会出现NTVDM遇到一个硬错误的提示。   
    如果在DOS实模式下,出现这种错误,   
    电脑就提示让你重启。

==========================

再有,如果用DEBUG的t命令的话,
先是t命令的相关压栈,
然后是中断的相关压栈吧
然后是中断的相关出栈
然后是t命令的相关出栈
继续单步...

[  duckgaga   发表于  2008-05-06 15:48  ]

==========quote from tamoto============
为什么用IRET从内中断INT 0H的中断例程中返回后,  
引发这个内中断的指令的下一个指令不响应单步就被执行了呢?  
------------------------ 
我的猜测: 
当执行除法指令之前,先判断一下是否发生除法溢出,如果会发生除法溢出,则触发除法溢出中断程序,这条除法指令并没有执行,在我们的中断程序返回之前,修改了栈中的偏移地址的值,使它指向除法指令的下一条指令,相当于这条指令替换了触发中断但并没有执行的那条除法指令,当执行完这条指令之后才会触发单步中断。给我们的错觉却是没有触发单步中断却执行了指令,其实是我们没有执行指令所以没有触发中断,执行了一条指令才触发了中断,并没有多执行一条指令。
==============================================
我认为这种解释比较合理,因为上边taotling也说:

============Quote from taotling========
是啊,这是为什么呀?讨论讨论。 


我今天在测试程序中用INT0H代替了DIV BX, 
结果用DEUBG 装载调试时,用T能单步跟踪进自己写的INT 0H中断例程中。 

如果测试程序中用DIV BX,当DIV BX引发INT 0H时, 
t命令单步跟踪是进不了INT 0H中断例程的...
=============================================
因此,我认为tomato的解释可能会更合理一点,但是怎样证明那个DIV没有被执行呢?还有得研究,呵呵……

[  taotling   发表于  2008-05-06 22:31  ]

(有可能引发INT 0H中断是像tomato说的那样,执行除法之前,先会判断一下是否会发生溢出,如果发生则触发INT 0H)

那么,如果那条DIV指令没有被执行,
可以把当时参加除法的相关寄存器的值存放在一个地方,
如果在进入INT 0H后,这些保存的寄存器的值与进入INT 0H前是一样的,那就是说没有执行DIV指令。

当然这样说比较勉强。

再看看下面的说法:

或者可以说DIV指令没有执行完,
因为可以看成是DIV指令引发的INT 0H中断,
CPU想要从DIV指令获取结果的时候,
发现有溢出,
就引发了INT 0H。
所以,可以看成是DIV指令没有被执行完(执行到要取结果时出现问题)。


一条指令没有被执行完,
那么当从这条指令所引发的中断返回时,IP应该是什么呢?

严格的说来,
返回的IP值不管是:
1.引发中断的指令的IP,
还是
2.引发中断的指令的下一条指令的IP,
都是一种错误的安排。
因为,出现这样的错误是致命的,
既然是致命的,就没有必要再把程序执行下去。

再看看引发INT 0H时压栈的IP:
如果这样的IP还是当初引发中断的那条指令的IP,
那么如果在中断例程中有返回的指令时,
这将使程序进入不断引发中断的死循环。

如果这样的IP是引发中断的下一条指令的IP,
当中断例程中有返回指令时,
那引发中断的指令并没有得到正常的执行,
而是跳过这条没有正常被执行的指令,
去执行其下一条指令,
中断的引发,说明存在错误,怎么能一错再错下去呢?

所以,可以推断一下,
对于引发了INT 0H的DIV指令,
原来(指系统自身的)INT 0H的中断例程的结束应该是一个直接终结程序回到DOS的指令,因为出现这样的中断,很明显错误是致命的,必须结束程序的继续运行。

所以在原INT 0H中不会存在什么IRET的返回指令。
因为这样,对于引发INT 0H时被压栈的IP被安排为引发中断的指令的IP,我想这是为寻找错误出在哪里而设吧,
也就是问题出现在哪里,错误出现在哪里,就通过这个引发中断时被压栈的IP值来寻找。

[  black   发表于  2008-05-07 13:53  ]

我认为是cpu本身的处理
当发生溢出错误的时候,则要求当前程序停止,等待修改

[  debugk   发表于  2008-09-01 09:36  ]

继续学习

[  游客   发表于  2008-09-17 21:51  ]

assume cs:code
code segment
start:mov ax,cs
mov ds,ax
mov si,offset do0
mov ax,0
mov es,ax
mov di,200h
mov cx,offset do0end-offset do0
cld
rep movsb
mov ax,0
mov ds,ax
mov bx,0
mov [bx],0200h
mov word ptr [bx+2],00h
mov ax,1000
mov bl,1
div bl
mov ax,4c00h
int 21h
do0:jmp short s
db "divide error!"
S:mov ax,0b800h
mov es,ax
mov bx,160*18+24*2
mov ax,0000
mov ds,ax
mov si,202h
mov al,2
mov cx,13
s2:
mov dl,byte ptr [si]
mov es:[bx],dl
mov byte ptr es:[bx+1],al
inc bx
inc bx
inc si
loop s2
iret
do0end:nop
code ends
end start
博主好好看看,我的是可以返回的。

[  游客   发表于  2008-09-17 21:54  ]

你的推断我认为不正确,你看cpu先读取指令倒缓存器中,紧接着ip指向下一条指令,再才进行指令执行的,你的这种验证和推断是不符合逻辑的,好好看看是不是这样的。

[  taotling   发表于  2008-09-22 14:14  ]

回: 
“cpu先读取指令倒缓存器中,紧接着ip指向下一条指令,再才进行指令执行的” 
这与我的验证并不冲突啊 

你把你的代码中的除法提出来,也就是把安装代码与除法代码分开执行试试,看是不是除法程序在执行的时候死循环?

[  taotling   发表于  2008-09-26 17:13  ]

但为什么把测试代码与安装代码放到一起,不用对IRET的出栈IP做特殊处理就可以正常返回呢?
而把安装程序与测试程序分开执行,IRET为什么要经过对出栈IP做一下处理才能正常返回?

试了一下好像与BX寄存器的再次使用有关(注意到除法中使用了BX寄存器),
因为在[游客 发表于 2008-09-17 21:51 ]的代码中,
在iret与其上的loop s2之间加上诸如MOV BX,07777H等使用BX寄存器的指令就会出现死循环的问题,
而加入MOV AX,XXXXH或MOV CX,XXXXH等是没问题的。   


哎,留着吧,最近比较忙没时间去深究,等缓过劲来了再说吧。

[  游客   发表于  2008-11-03 11:58  ]

看不懂

[  glasses   发表于  2009-02-18 03:18  ]

佩服楼主的精神,我写的时候,太粗心,根本没注意到.
在论坛看到了之后.特别感动楼主的精神.
我也GOOGLE了下.
http://topic.csdn.net/u/20081222/08/9f1c098f-b4a9-4113-901d-a4efc9214078.html

[  游客   发表于  2009-03-08 02:43  ]

楼主的问题,我用debug测试了一下!
    证明1:对于执行div指令引发的溢出错误,由于除法并没有被成功执行,所以入栈的仍然是此div指令的ip,中断处理程序执行完后,iret返回到的仍是此div指令,所以中断程序被循环调用,出现死循环!
    证明2:对于有人说将div指令直接换成int 0我的测试,证明可以正常返回!原因应该是int 0虽然与执行div发生除法溢出调用的中断程序一样,但由div引发溢出调用中断,div本身这条指令没执行成功,入栈时记录的是它的IP,而对与int 0指令,其本身是得以正确执行了的,所以入栈时记录的是它下一条指令的IP,也就是mov ax,4c00h所对应的IP,所以能正常返回了!
   个人拙见,欢迎大家交流意见!?

[  tianyanly1984   发表于  2009-03-08 02:48  ]

楼主的问题,我用debug测试了一下! 
    证明1:对于执行div指令引发的溢出错误,由于除法并没有被成功执行,所以入栈的仍然是此div指令的ip,中断处理程序执行完后,iret返回到的仍是此div指令,所以中断程序被循环调用,出现死循环! 
    证明2:对于有人说将div指令直接换成int 0我的测试,证明可以正常返回!原因应该是int 0虽然与执行div发生除法溢出调用的中断程序一样,但由div引发溢出调用中断,div本身这条指令没执行成功,入栈时记录的是它的IP,而对与int 0指令,其本身是得以正确执行了的,所以入栈时记录的是它下一条指令的IP,也就是mov ax,4c00h所对应的IP,所以能正常返回了! 
   个人拙见,欢迎大家交流意见!?

[  cuttlefish   发表于  2009-05-09 19:58  ]

“中断”,分为三种即陷阱,中断和异常,他们的英文分别是 trap,interrupt 和 exception。

陷阱:由 trap 指令引起,恢复后 CPU 执行下一条指令
中断:由硬件电平引起,恢复后 CPU 执行下一条指令
异常:由软件指令引起,恢复后 CPU 重新执行该条指令


这样就明白了吧:异常是指一条指令会引起 CPU 的不快,比如除零。

 
 请输入验证码  (提示:点击验证码输入框,以获取验证码