. : : Assembly Language : : .  |  首页  |  我提出的问题  |  我参与的问题  |  我的收藏  |  消息中心   |  游客  登录  | 
刷新 | 提问 | 未解决 | 已解决 | 精华区 | 搜索 |
  《汇编语言》论坛 ->外中断
  管理员: assembly   [回复本贴] [收藏本贴] [管理本贴] [关闭窗口]
主题 : :  关于int 9和15.4/15.5的讨论  [待解决] 回复[ 4次 ]   点击[ 526次 ]  
imyeyeslove
[帖 主]   [ 发表时间:2009-09-27 01:49 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2009-09-22 19:30
在网上看到些关于int 9的问题和讨论,用的动词是--“模拟”“编写”“安装”。。有些难受,

遇到的问题:
1.   能否不调用原int 9例程
2.   代码中没有int的显式调用,之前的程序为何有
3.   检测点15.1
4.   多了个pushf,之前的程序为何没加

对于原因我们分析有2:
1.  从12章开始自己修改中断例程而慢慢形成的惯性思维
2.  15.4和15.5的标题以及内容对我们误导

请记住,15章前我们确实在修改或编写中断例程,但对于int 9,至少《汇编语言》让我们无能为力,我们在15章做的,严格的讲连对于这个中断例程作用的扩充都不算。

子程序和中断例程都分2块--调用+实现:
call 标号,        程序体(从标号到ret)
int n,                n号中断的程序体(到iret结束)

对于int 9的这2部分,我们什么都没做,除了把进入其实现的入口转移了地方。。。

为方便理解,我们姑且先把它叫作“键盘驱动例程”,并以15.4的程序为例

作者写的很清楚,我们不能像之前那样直接扔掉中断例程,因为它处理了按键输入的很多细节,否则CPU怎么知道你的指头在键盘上干了什么。如果扔掉,那我们自己写的代码只能让系统识别ESC这1个键(变色)。我们确实也只做了这件事。

我们知道,
call做了-- (push cs) push ip
ret做了        -- pop ip

int做了:
1. pushf
2. IF/TF = 0
3. push cs
4. push ip
5. 让cpu到新的cs:ip处 (请一定记好这几步!!并与iret对比)

iret做了:
。。。                        (特定功能实现代码)
pop ip
pop cs
popf                        (也请一定记好)

在15章前,(除了int 21h)我们的程序里有类似int 7ch这样的int显式调用,完成了上述5步。而15.4和15.5的程序中却没有!!

因为“键盘输入到达60h端口后,就会引发9号中断,CPU则转去执行int 9中断例程”,所以当执行程序时只要有键盘输入,就会隐式调用int 9,遂我们写的代码中不需要显式声明!

那么此时,
1. pushf
2. IF/TF = 0
3. push cs
4. push ip
5. 让cpu到新的cs:ip处
均已执行!!

接着根据新cs:ip的引导,我们来到了自己写的代码段,继续执行:
push ax
push bx
push es
。。。        (只分析栈)
pushf        (有网友说flags已经在之前的int调用下入栈了,这句貌似多余。下面分析)

监测点15.1省略的代码段(隐式调用的int已置IF/TF为0,所以才能省略)

call “键盘驱动例程”,=
{
push cs
push ip
}

“键盘驱动例程” =
{
。。。
pop ip
pop cs
popf        (这3步是iret)
}
...
pop es
pop bx
pop ax
iret =
{
pop ip
pop cs
popf
}

您看出什么了?


曾经,我们--

键盘输入->

int 9中断 =
{
pushf          
push cs
push ip          (只管栈)        
}

->

“键盘驱动程序” =
{
pop ip
pop cs
popf        (这3步是iret)
}

如此和谐!!

但因为在2者间插入诸如push ax, push bx,call(特别是call。。)这样影响int 9幸福生活的不和谐因素,导致flags/cs/ip进出栈顺序混乱。。

所以,我们只能配合call而加入pushf,2者一同去“中和”“抵消”下面的“键盘驱动例程”返回时的iret(它本就是身份高贵的中断例程,所以是iret而不是ret)

而最初的int调用产生的
pushf, push cs, push ip
由我们自己编写的代码,在最后由iret中和
pop ip, pop cs, popf

综上,栈的发展:
pushf                (int)
push cs                (int)
push ip                (int)
push ax        
push bx
push es
pushf
push cs                (call)
push ip                (call)

pop ip                (iret 例程的)
pop cs                (iret 例程的)
popf                (iret 例程的)
pop es
pop bx
pop ax
pop ip                (iret 我们写的)
pop cs                (iret 我们写的)
popf                (iret 我们写的)


总结:
1.   15.4.2中的误导--“int过程的模拟”“标志寄存器入栈,可用pushf实现”。
int已经隐式完成,标志寄存器已经入栈,pushf在实现“中和”“抵消”。这也是15章前我们写的程序中没有多加“pushf”的原因。

2.   中断例程的2部分--调用+实现,我们都没有改动,准确的说是没能力。
我们做的只是改变实现部分调用的入口(调用时机),也就是在该“键盘驱动例程”的前后加了几行代码,仅此而已。

希望与大家讨论
ldlihuanfa
[第1楼]   [ 回复时间:2010-02-04 10:36 ]   [引用]   [回复]   [ top ] 
荣誉值:6
信誉值:0
注册日期:2009-12-18 19:53
作者写的很清楚,我们不能像之前那样直接扔掉中断例程,因为它处理了按键输入的很多细节,否则CPU怎么知道你的指头在键盘上干了什么。如果扔掉,那我们自己写的代码只能让系统识别ESC这1个键(变色)。我们确实也只做了这件事。

关于这句话,我也是在想,不过程序只要能识别esc就行啊,程序的目的不就是变色吗?疑惑中
ldlihuanfa
[第2楼]   [ 回复时间:2010-03-07 17:14 ]   [引用]   [回复]   [ top ] 
荣誉值:6
信誉值:0
注册日期:2009-12-18 19:53
关于第二部分,如果不要那个pushf,首先我想,按下esc,中断过程发生,标志入栈,然后是cs,ip入栈,丢开寄存器不管,然后执行到call指令,又是cs,ip入栈,栈中是两个ip,cs ,然后标志。
接下来原in9,里面最后是iret,cs,ip出栈,接下来。。不太对了。。

如果加入pushf,那么标志入栈,cs,ip入栈,接下再是标志,然后又是cs,ip,栈中是ip,cs,标志,ip,cs
执行原in9,到iret出来一个ip,cs,接来标志出栈,原in9执行完后,新in9又有一个iret,正好套上。。
mgf1988629
[第3楼]   [ 回复时间:2010-03-13 22:40 ]   [引用]   [回复]   [ top ] 
荣誉值:14
信誉值:2
注册日期:2009-11-30 11:46
很精辟,大体根我一样,然而程步骤不知是否根各位同窗一样,太多了很难写,各位有兴趣到问题1,看在那儿有回复!
752052871
[第4楼]   [ 回复时间:2010-11-04 19:27 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2010-10-16 19:16
终于明白了。。我就知道汇编网上的神人多。。
谢谢
需要登录后才能回帖 -->> 请单击此处登录
    Copyright © 2006-2024   ASMEDU.NET  All Rights Reserved