|
主题 : : 检测点15.1的一个疑问 [待解决] |
回复[ 13次 ]
点击[ 784次 ] | |
|
|
|
|
[帖 主]
[ 发表时间:2009-08-10 23:01 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2009-07-30 00:44 |
对于15.1的答案精简为
pushf
call dword ptr ds:[0]
我觉得似乎不用pushf了吧,因为这是中断例程,占用的是中断类型码9的中断向量,
那在中断发生时,中断过程中,标志寄存器入栈是cpu硬件完成的啊,而且IF和TF也都由硬件置0,干嘛还需要再次pushf呢?
不明白! | | |
|
|
|
|
[第1楼]
[ 回复时间:2009-08-15 15:06 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:5
注册日期:2009-07-21 17:17 |
顶上去,我对这里也不大了解,int 9不是把这些都包括了吗,既然后面调用了int 9了 为什么还是执行这些int 9执行的代码 那不重复了吗?
还有那个in al,60h | | |
|
|
|
|
[第2楼]
[ 回复时间:2009-08-17 09:52 ]
[引用]
[回复]
[ top ] | |
荣誉值:6
信誉值:0
注册日期:2009-07-26 17:16 |
CALL原来的中断例程时有一个IRET,改写后的中断例程最后还有一个IRET。为了保证堆栈不乱,所以得加个PUSHF。不知我的回答对不对。 | | |
|
|
|
|
[第3楼]
[ 回复时间:2009-08-17 10:27 ]
[引用]
[回复]
[ top ] | |
荣誉值:61
信誉值:4
注册日期:2008-10-14 16:29 |
这里是在模拟中断,是一个软调用,就想我们自己调子函数,所以,中断过程中保存标志寄存器的操作当然要我么你自己操作的。 | | |
|
|
|
|
[第4楼]
[ 回复时间:2009-09-04 14:12 ]
[引用]
[回复]
[ top ] | |
荣誉值:22
信誉值:12
注册日期:2009-08-28 00:17 |
这个是在你自己的中断处理程序里面,模拟CPU去执行BIOS提供的int 9h中断。
CPU在执行中断处理程序前,做了什么工作。你的中断处理程序,在调用int 9h中断就一样要做什么工作。CPU干了以下4件事:
1.取中断类型码,这个我们已经知道是9,所以不用搞。
2.标志寄存器入栈。所以我们的中断处理程序也要pushf。这是必须的。
3.TF,IF=0。因为已经在中断处理程序里了,所以保证了TF,IF为0.所以15.1(1)里面说这一步也可以忽略。
4.CS,IP依次入栈。CALL就干了这个事情。
CPU为什么要这样呢?
因为BIOS提供的INT 9H中断,最后有一个IRET。
IRET干了以下3件事,POP IP,POP CS,POPF.这样就恢复了中断以前的CPU现场。
在我们这个程序中,如果你把PUSHF省略了,你自己想想有何后果吧。 | | |
|
|
|
|
[第5楼]
[ 回复时间:2009-10-05 13:19 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2009-10-05 11:08 |
今天看到这章了,没有认真的想,直接跑到这儿来找答案了,看了楼上的回答好像懂了,这儿把我的理解说出来让高手们检查检查看我理解错误没有。估计是这样的,其实从cpu执行中断开始到最后用int9ret段中的iret退出这个中断一共有两个周期的压栈和出栈。
第一个:cpu开始执行中断过程时压的,就是(1)标志寄存器入栈,if=0,tf=0;(2)cs,ip入栈;在这两部中就完成了第一次压栈-------他所对应的出栈是程序最后的那个int9ret段中的iret;
第二个:就是我们为什么要设置pushf的原因了,同时cs ,ip也需要入栈,那么他是在哪儿入栈的呢?就是这句 call dword ptr ds:[0] ,他的功能相当于(1)cs,ip入栈;(2)(ip)=((ds)*16+0),(cs)=((ds)*16+2)-------他所对应的出栈在哪儿呢?估计就是在我们计算机原来的那个bios提供的int 9中断中,其中最后的那句iret; | | |
|
|
|
|
[第6楼]
[ 回复时间:2009-10-05 13:22 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2009-10-05 11:08 |
|
|
|
|
|
[第7楼]
[ 回复时间:2011-09-05 21:46 ]
[引用]
[回复]
[ top ] | |
荣誉值:31
信誉值:3
注册日期:2009-06-15 19:20 |
必须要~
整个模拟中断例程的顺序结构如下:
1、调用原9号中断例程
2、程序
3、恢复及返回
如果没有pushf而直接用call的话,那么细化下上面的步骤就是:
(1)pushf,TF=IF=0,push cs\push ip
(2)原例程处理代码
(3)pop ip,pop cs,popf
以上三步即为上述1中的分步
(4)同上2
(5)同上3
说到这儿应该就可以看出来了,如果没有pushf的话在call的时候已经完成popf这个步骤了,那你后面的程序如果涉及到flag的改动你根本没辙处理。 | | |
|
|
|
|
[第8楼]
[ 回复时间:2011-09-06 00:19 ]
[引用]
[回复]
[ top ] | |
荣誉值:118
信誉值:0
注册日期:2011-07-07 22:59 |
在call时又不压标志寄存器,为了保证堆栈平衡,所以得将它压栈。 | | |
|
|
|
|
[第9楼]
[ 回复时间:2011-12-06 14:00 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2011-11-11 23:27 |
我同意 lengren 的说法
简单的说 就是 这样:
第一 1. 键盘引发9h中断 pushf ,TF=0,IF=0,cs:ip 入栈
第二 2. pushf
第三 3. call dword ptr (cs:ip) ;入站 第四处的CS:ip,并执行 call所指向的程序
第四 4. ......一些指令
第五 5. 第三处call指的是BIOS的9h号中断例程,里面含有iret,会出栈第三处和第二处
第六 6. ......一些指令
第七 7. iret 这条出栈第一处 入栈的 IP,CS ,Flag
这个时候 程序CS:ip 指向的是 键盘引发9h号中断前的 下一条指令 | | |
|
|
|
|
[第10楼]
[ 回复时间:2012-02-27 20:01 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2009-01-17 12:29 |
lengren分析很对,我第二次看,才仔细想通这里。并debug发现确实如此 | | |
|
|
|
|
[第11楼]
[ 回复时间:2019-02-25 15:45 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:2
注册日期:2011-11-27 16:20 |
我也有同样的疑问,看了上面的各个回答,我觉得还是有点问题,有些回答没搞清什么是中断、中断过程、中断向量、中断例程。
首先中断是一种机制,不存在有执行中断这种说法,顶多叫响应中断,根据中断向量找到中断处理程序,也就是中断例程,最后执行中断例程。
发送中断时,计算机硬件完成中断过程,一旦中断过程完成了,就开始执行中断例程,中断例程最后返回用的是iret,也就是出栈ip、cs、状态寄存器。
在中断过程中,硬件会压栈ip、cs、状态寄存器,还会置0 tf、if标志,所以中断例程用iret返回。这里的iret与中断过程中的操作配对操作。
而int 9是引发中断,到底引发中断里面包不包含中断过程操作,书上说的比较含糊。另外int 9引发中断和中断过程到底哪个会压栈状态寄存器书上可能说的也不准确,因为从论坛搜索到书本第一版里面能看到中断过程不包含状态寄存器压栈。
如果按照5楼的推断,那么可以去掉pushf,然后把iret改成ret,实际我调试测试这样是会出问题的。 | | |
|
|
|
|
[第12楼]
[ 回复时间:2019-02-25 16:16 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:2
注册日期:2011-11-27 16:20 |
中断过程压栈一次,pushf压栈一次,call压栈一次,感觉应该是压栈三次。 | | |
|
|
|
|
[第13楼]
[ 回复时间:2019-02-25 16:26 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:2
注册日期:2011-11-27 16:20 |
仔细想想,5楼还是有道理的,开始cs、ip、标志寄存器入栈,最后自定义的中断例程用iret将他们出站,call调用旧例程,只压栈了cs、ip,而旧例程用的是iret出栈的,因此必须用pushf+call压栈的cs、ip形成配对。 | | |