|
主题 : : 如何处理中断结束? [待解决] |
回复[ 23次 ]
点击[ 1307次 ] | |
|
|
|
|
[帖 主]
[ 发表时间: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为什么不行呢? | | |
|
|
|
|
[第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就是返回到调用你的程序之前的那个操作系统(程序)。 | | |
|
|
|
|
[第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
不知道这样理解有什么问题... | | |
|
|
|
|
[第3楼]
[ 回复时间:2008-03-26 11:25 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2008-01-06 17:59 |
难道cpu对除法溢出的中断和应用程序安装的中断处理级别不一样? | | |
|
|
|
|
[第4楼]
[ 回复时间:2008-03-26 14:33 ]
[引用]
[回复]
[ top ] | |
荣誉值:405
信誉值:0
注册日期:2008-01-19 14:51 |
我的想法是:除法溢出是内中断,当有除法溢出的时候,系统调用的中断,并不是应用程序调用的中断,所以在应用程序中并没有保存寄存器的操作,如果用iret指令的话,中断程序不会返回到应用程序中去接着执行mov ax,4c00h
int 21h
不知道我的理解是否正确 | | |
|
|
|
|
[第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还是有区别的啊... | | |
|
|
|
|
[第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入栈是怎么回事? | | |
|
|
|
|
[第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的特殊情况,
要做一下处理。 | | |
|
|
|
|
[第8楼]
[ 回复时间:2008-03-31 10:45 ]
[引用]
[回复]
[ top ] | |
荣誉值:405
信誉值:0
注册日期:2008-01-19 14:51 |
看完楼上taotling的解说了,我感觉受益匪浅,恍然大悟,原来是这样的!很佩服taotling的怀疑研究精神。感觉很有意思,汇编的乐趣也许就在此吧。它能让我们去自己研究,最终会有结果证实我们判断的对错,在这个过程中我们心中充满的是好奇,兴趣,当我们研究出结果,真正通过自己的研究弄明白一个问题的时候,我们不仅会有一种发自内心的高兴,一种发自内心的成就感,同时也会增加一份自信和满足。当真正体会到这些的时候,我想我们才有资格去评判汇编到底重要不重要,汇编到底难学不难学,汇编到底枯燥不枯燥? | | |
|
|
|
|
[第9楼]
[ 回复时间:2008-03-31 12:18 ]
[引用]
[回复]
[ top ] | |
荣誉值:53
信誉值:0
注册日期:2008-02-09 02:55 |
|
|
|
|
|
[第10楼]
[ 回复时间:2008-04-01 18:03 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2008-01-06 17:59 |
不好意思,最近较忙,不能及时跟进你们的答复,谢谢大家
to taoling
谢谢你的分析,不过我还是有些疑虑
看了你的证明后,你的结论是:INT 0H可以用IRET返回,类似div的系统中断调用区别在于ip入栈时用的当前指令而非中断的下条指令,因此造成循环执行中断
问题:使用debug的方式调试,遇到系统中断后会否做些别的动作,我的意思是当前栈的数据被改动,可能是debug程序的特定动作,假设当前指令是debug保存下来呢?(当然,是假设,我也不知道是否如此)如果是该情况的话,我对你上面的证明还是有疑惑的...... | | |
|
|
|
|
[第11楼]
[ 回复时间:2008-04-02 15:46 ]
[引用]
[回复]
[ top ] | |
荣誉值:53
信誉值:0
注册日期:2008-02-09 02:55 |
|
|
|
|
|
[第12楼]
[ 回复时间:2008-05-06 13:11 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2008-04-01 17:12 |
从层层迷雾中看到了阳光!!!
收获N多!!!!!!!
继续学习 | | |
|
|
|
|
[第13楼]
[ 回复时间:2008-05-06 15:26 ]
[引用]
[回复]
[ top ] | |
荣誉值:44
信誉值:0
注册日期:2008-04-11 13:33 |
这个问题很值得研究,呵呵,taotling说得很好,收获…… | | |
|
|
|
|
[第14楼]
[ 回复时间:2008-09-01 09:34 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2008-06-13 10:30 |
|
|
|
|
|
[第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指向下一条指令,再才进行指令执行的,你的这种验证和推断是不符合逻辑的,好好看看是不是这样的。 | | |
|
|
|
|
[第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不光是调用我们写的溢出显示程序,还调用其它一些程序。是什么我不太清楚,这只是我的感觉. | | |
|
|
|
|
[第17楼]
[ 回复时间:2008-09-26 17:14 ]
[引用]
[回复]
[ top ] | |
荣誉值:53
信誉值:0
注册日期:2008-02-09 02:55 |
但为什么把测试代码与安装代码放到一起,不用对IRET的出栈IP做特殊处理就可以正常返回呢?
而把安装程序与测试程序分开执行,IRET为什么要经过对出栈IP做一下处理才能正常返回? | | |
|
|
|
|
[第18楼]
[ 回复时间:2008-11-06 17:21 ]
[引用]
[回复]
[ top ] | |
荣誉值:152
信誉值:3
注册日期:2008-01-24 21:26 |
所以我认为iret返回的应该是下条指令地址。用iret返回的div 溢出的原因可能是cpu不光是调用我们写的溢出显示程序,还调用其它一些程序。是什么我不太清楚,这只是我的感觉.
----------------
我也这样认为,由于这个溢出过程调用了不只一个中断例程,而你int 0中的iret可能返回到了其他中断例程的程序中。至于说调用子程序的时候,我觉得肯定是将下一条指令的cs,ip进行保存的,不可能对于本质一样的操作,有两个不同的处理方式。 | | |
|
|
|
|
[第19楼]
[ 回复时间:2009-02-18 03:15 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2009-01-08 08:37 |
|
|
|
|
|
[第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,所以能正常返回了!
个人拙见,欢迎大家交流意见!? | | |
|
|
|
|
[第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 | | |
|
|
|
|
[第22楼]
[ 回复时间:2009-04-21 15:57 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2009-04-15 18:50 |
|
|
|
|
|
[第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 ;设置显示的屏幕缓冲区的位置
将这两节位置颠倒就可以正确返回了,大家也可以试试,我电脑是这样的。
可我想不明白是什么原因,谁能帮忙解释下!!!! | | |
|