. : : Assembly Language : : .  |  首页  |  我提出的问题  |  我参与的问题  |  我的收藏  |  消息中心   |  游客  登录  | 
刷新 | 提问 | 未解决 | 已解决 | 精华区 | 搜索 |
  《汇编语言》论坛 ->内中断
  管理员: assembly   [回复本贴] [收藏本贴] [管理本贴] [关闭窗口]
主题 : :  如何处理中断结束?  [待解决] 回复[ 23次 ]   点击[ 1307次 ]  
wesom
[帖 主]   [ 发表时间:2008-03-25 14:30 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2008-01-06 17:59
书上的例子使用的是调用另外的中断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为什么不行呢?
younggay
[第1楼]   [ 回复时间:2008-03-25 19:52 ]   [引用]   [回复]   [ top ] 
荣誉值:273
信誉值:0
注册日期:2008-01-23 20:23
iret子程序后利用你主程序的栈来恢复cs,ip,而mov ax,4c00h int 21h是调用了另一个中断程序,这个程序根据功能标号对应功能例程,比如mov ah,4cH就是返回到调用你的程序之前的那个操作系统(程序)。
wesom
[第2楼]   [ 回复时间:2008-03-26 11:20 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2008-01-06 17:59
do0:
...
mov ax,4c00h
int 21h      ;按楼上理解,这里如果用iret就不返回主程序了吗?我觉的不是
doend:
按我自己的理解,应该是iret执行完--》 执行主程序的 mov ax,4c00h int 21h 
不知道这样理解有什么问题...
wesom
[第3楼]   [ 回复时间:2008-03-26 11:25 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2008-01-06 17:59
难道cpu对除法溢出的中断和应用程序安装的中断处理级别不一样?
tomato
[第4楼]   [ 回复时间:2008-03-26 14:33 ]   [引用]   [回复]   [ top ] 
荣誉值:405
信誉值:0
注册日期:2008-01-19 14:51
我的想法是:除法溢出是内中断,当有除法溢出的时候,系统调用的中断,并不是应用程序调用的中断,所以在应用程序中并没有保存寄存器的操作,如果用iret指令的话,中断程序不会返回到应用程序中去接着执行mov ax,4c00h
int 21h
不知道我的理解是否正确
wesom
[第5楼]   [ 回复时间:2008-03-27 12:39 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2008-01-06 17:59
我做了个测试,
code segment 
   begin : mov ax,data 
           mov ds,ax 
           mov ax,1000h 
           mov bh,1 
           div bh  ;此处改为int 0就得到预期的结果
           mov ax,4c00h 
           int 21h 
code ends 
看来cpu对除法溢出的中断div和直接使用int 0还是有区别的啊...
taotling
[第6楼]   [ 回复时间:2008-03-30 17:19 ]   [引用]   [回复]   [ top ] 
荣誉值:53
信誉值:0
注册日期:2008-02-09 02:55
在楼上程序中显式调用INT 0与发生除法溢出有什么区别?

上面的程序改了后你同样不能返回主程序啊。





另外:
tomato所说的:
我的想法是:除法溢出是内中断,当有除法溢出的时候,系统调用的中断,并不是应用程序调用的中断,所以在应用程序中并没有保存寄存器的操作...

系统调用中断是什么意思?
系统调用中断也是在应用程序执行的过程中调用的,也就是INT 0被调用的时候,
CPU正在执行应用程序的某一指令(比如说一个除法),
那你说此时的CS:IP不应该是应用程序的CS:IP?而是别的程序的CS:IP?
不是这样的吧?

书上230页就写着0号中断信息的引发过程:
(1)取得中断类型码0
(2)标志寄存器入栈,TF、IF设置为0
(3)CS、IP入栈
(4)(IP)=(0*4),(CS)=(0*4+2)


那这里的CS、IP入栈是怎么回事?
taotling
[第7楼]   [ 回复时间:2008-03-30 19:38 ]   [引用]   [回复]   [ top ] 
荣誉值:53
信誉值:0
注册日期:2008-02-09 02:55
回到楼主的问题上来吧:下面写的有些长,也许没有人能够仔细的看下去,
但是没关系,细节的东西,总是留给有心人的,谢谢楼主提出的问题,
让我有更多的思考,同时谢谢tomato的猜测,没有tomato的帖子,
我也不会去深研INT 0H被系统调用时压栈的IP、CS是什么........




首先看看安装中断例程的代码:
===============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的特殊情况,
要做一下处理。
tomato
[第8楼]   [ 回复时间:2008-03-31 10:45 ]   [引用]   [回复]   [ top ] 
荣誉值:405
信誉值:0
注册日期:2008-01-19 14:51
看完楼上taotling的解说了,我感觉受益匪浅,恍然大悟,原来是这样的!很佩服taotling的怀疑研究精神。感觉很有意思,汇编的乐趣也许就在此吧。它能让我们去自己研究,最终会有结果证实我们判断的对错,在这个过程中我们心中充满的是好奇,兴趣,当我们研究出结果,真正通过自己的研究弄明白一个问题的时候,我们不仅会有一种发自内心的高兴,一种发自内心的成就感,同时也会增加一份自信和满足。当真正体会到这些的时候,我想我们才有资格去评判汇编到底重要不重要,汇编到底难学不难学,汇编到底枯燥不枯燥?
taotling
[第9楼]   [ 回复时间:2008-03-31 12:18 ]   [引用]   [回复]   [ top ] 
荣誉值:53
信誉值:0
注册日期:2008-02-09 02:55
呵呵,很高兴有人能够有耐心看懂我说什么!
wesom
[第10楼]   [ 回复时间:2008-04-01 18:03 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2008-01-06 17:59
不好意思,最近较忙,不能及时跟进你们的答复,谢谢大家
to taoling
谢谢你的分析,不过我还是有些疑虑
看了你的证明后,你的结论是:INT 0H可以用IRET返回,类似div的系统中断调用区别在于ip入栈时用的当前指令而非中断的下条指令,因此造成循环执行中断
问题:使用debug的方式调试,遇到系统中断后会否做些别的动作,我的意思是当前栈的数据被改动,可能是debug程序的特定动作,假设当前指令是debug保存下来呢?(当然,是假设,我也不知道是否如此)如果是该情况的话,我对你上面的证明还是有疑惑的......
taotling
[第11楼]   [ 回复时间:2008-04-02 15:46 ]   [引用]   [回复]   [ top ] 
荣誉值:53
信誉值:0
注册日期:2008-02-09 02:55
我不开两处了,这里的问题再继续讨论转到我Blog里去吧:
http://www.asmedu.net/blog/user/postcontent.jsp?neighborId=7740&kindId=10825&postId=13854&readSg=1&vs=1
hncscwc
[第12楼]   [ 回复时间:2008-05-06 13:11 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2008-04-01 17:12
从层层迷雾中看到了阳光!!!
收获N多!!!!!!!
继续学习
duckgaga
[第13楼]   [ 回复时间:2008-05-06 15:26 ]   [引用]   [回复]   [ top ] 
荣誉值:44
信誉值:0
注册日期:2008-04-11 13:33
这个问题很值得研究,呵呵,taotling说得很好,收获……
debugk
[第14楼]   [ 回复时间:2008-09-01 09:34 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2008-06-13 10:30
收获很多,谢谢TAOTLING
nakamura
[第15楼]   [ 回复时间:2008-09-17 21:59 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2008-09-09 18:39
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
我的怎么可以返回啊!你的推断我认为不正确,你看cpu先读取指令倒缓存器中,紧接着ip指向下一条指令,再才进行指令执行的,你的这种验证和推断是不符合逻辑的,好好看看是不是这样的。
fenglixin70953
[第16楼]   [ 回复时间:2008-09-23 12:48 ]   [引用]   [回复]   [ top ] 
荣誉值:2
信誉值:0
注册日期:2008-01-23 09:03
楼上的代码放在一个程序中是可以完成,我做了个试验,溢除程序与安装程序分别来写的话,安装程序用iret返回,溢除程序确实不能正常返回,进入了死循环。
  安装程序:
assume cs:code
code segment
     start: mov ax,cs
            mov ds,ax
            mov ax,0
            mov es,ax
            mov di,200h
            mov si,offset divide
            mov cx,offset divide_end-offset divide
            cld
            rep movsb
            
            mov word ptr es:[0],200h
            mov word ptr es:[2],0h
            
            mov ax,4c00h
            
           int 21h
           
      divide:jmp short ok
            db 'divide error'
          ok:mov ax,cs
            mov ds,ax
            mov si,202h
            mov ax,0b800h
            mov es,ax
            mov di,160*3
            mov cx,12
           s:mov al,[si]
             mov es:[di][bx],al
             inc si
             add di,2
             loop s
             add bx,12  ;注意这个,为了让循环能直观的看出来,我这里让每一次进入中断 bx都加12
         iret
          divide_end:nop
            
            code ends
            end start

溢出程序:
assume cs:code
code segment
start:mov dl,1
      mov ax,1000
      mov bx,0
      div dl    ;用div溢出调用中断
      mov ax,4c00h
      int 21h
      code ends
      end start
;这个程序执行后进行死循环。说明了中断程序运行后返回的cs:ip指向了div dl这条指令.

下面这个程序用int 0调用中断
assume cs:code
code segment
start:mov dl,1
      mov ax,1000
      mov bx,0
      int 0
      mov ax,4c00h
      int 21h
      code ends
      end start
结果是可以正常反回,说明中断程序执行后,cs:ip指向int 0的下一条指令。
由此int 与iret才是一对指令,正如call 与ret
所以我认为iret返回的应该是下条指令地址。用iret返回的div 溢出的原因可能是cpu不光是调用我们写的溢出显示程序,还调用其它一些程序。是什么我不太清楚,这只是我的感觉.
taotling
[第17楼]   [ 回复时间:2008-09-26 17:14 ]   [引用]   [回复]   [ top ] 
荣誉值:53
信誉值:0
注册日期:2008-02-09 02:55
但为什么把测试代码与安装代码放到一起,不用对IRET的出栈IP做特殊处理就可以正常返回呢? 
而把安装程序与测试程序分开执行,IRET为什么要经过对出栈IP做一下处理才能正常返回?
crazyman
[第18楼]   [ 回复时间:2008-11-06 17:21 ]   [引用]   [回复]   [ top ] 
荣誉值:152
信誉值:3
注册日期:2008-01-24 21:26
所以我认为iret返回的应该是下条指令地址。用iret返回的div 溢出的原因可能是cpu不光是调用我们写的溢出显示程序,还调用其它一些程序。是什么我不太清楚,这只是我的感觉.
----------------
我也这样认为,由于这个溢出过程调用了不只一个中断例程,而你int 0中的iret可能返回到了其他中断例程的程序中。至于说调用子程序的时候,我觉得肯定是将下一条指令的cs,ip进行保存的,不可能对于本质一样的操作,有两个不同的处理方式。
glasses
[第19楼]   [ 回复时间:2009-02-18 03:15 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2009-01-08 08:37
我写的时候,还没注意到这个问题.汗一个...
特意去G了下.http://topic.csdn.net/u/20081222/08/9f1c098f-b4a9-4113-901d-a4efc9214078.html
感谢大家.
感谢汇编网.给我提供一个向大家学习的机会.
tianyanly1984
[第20楼]   [ 回复时间:2009-03-08 02:49 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:4
注册日期:2008-12-12 00:18
楼主的问题,我用debug测试了一下! 
    证明1:对于执行div指令引发的溢出错误,由于除法并没有被成功执行,所以入栈的仍然是此div指令的ip,中断处理程序执行完后,iret返回到的仍是此div指令,所以中断程序被循环调用,出现死循环! 
    证明2:对于有人说将div指令直接换成int 0我的测试,证明可以正常返回!原因应该是int 0虽然与执行div发生除法溢出调用的中断程序一样,但由div引发溢出调用中断,div本身这条指令没执行成功,入栈时记录的是它的IP,而对与int 0指令,其本身是得以正确执行了的,所以入栈时记录的是它下一条指令的IP,也就是mov ax,4c00h所对应的IP,所以能正常返回了! 
   个人拙见,欢迎大家交流意见!?
linwangfeng
[第21楼]   [ 回复时间:2009-04-21 15:56 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2009-04-15 18:50
TO nakamura
我用你写的可以正确返回,可我用自己的就不行,最后就一直死在那里不动了。
我用的就是书上的代码:
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 es,ax
        mov word ptr es:[0*4],200h
        mov word ptr es:[0*4+2],0

        mov ax,4c00h
        int 21h

do0:        jmp short do0start
        db "overflow!"

do0start:
        mov ax,cs
        mov ds,ax
        mov si,202h

        mov ax,0b800h
        mov es,ax
        mov di,160*18+24*2

        mov cx,8

s:        mov al,[si]
        mov es:[di],al
        mov byte ptr es:[di+1],2
        inc si
        add di,2
        loop s

        iret
do0end:        nop

code ends
end start
linwangfeng
[第22楼]   [ 回复时间:2009-04-21 15:57 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2009-04-15 18:50
我怎么都找不出来你的与这个哪里不同!!!!!!
linwangfeng
[第23楼]   [ 回复时间:2009-04-21 18:09 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2009-04-15 18:50
折腾了几个钟头,找到了两个的不同之处:
就是  do0start段的两节
 (1)    mov ax,cs 
       mov ds,ax 
       mov si,202h ;设置所输出的字符串位置

 (2)   mov ax,0b800h 
       mov es,ax 
       mov di,160*18+24*2 ;设置显示的屏幕缓冲区的位置
将这两节位置颠倒就可以正确返回了,大家也可以试试,我电脑是这样的。
可我想不明白是什么原因,谁能帮忙解释下!!!!
需要登录后才能回帖 -->> 请单击此处登录
    Copyright © 2006-2024   ASMEDU.NET  All Rights Reserved