王小2 发表于 2016-12-15 11:39:08

关于甲鱼老师讲的第十章call指令和检测点10.2的问题

刚在学习小甲鱼老师的汇编视频,看到第十章call指令,讲的是cpu执行call指令时,进行两步操作:1、将当前的ip或cs和ip压入栈中;2、转移(jmp)。
本人认为老师讲的将当前的ip压入栈中这样说不恰当,应该是IP的值先变成call指令后的第一个字节的地址,然后才被压入栈中。然而老师在讲后边call和ret指令时,又强调了ip指向了call下一条指令,再将ip入栈。
这样就给很多初学汇编的同学造成了误解(包括我本人),以为两种指令的ip入栈不同,导致很多同学发帖问检测点10.2的答案ax的值为什么是6,表示不懂。以下为检测点10.2

下面的程序执行后,ax中的数值为多少?

内存地址    机器码      汇编指令   执行后情况

1000:0   b8 00 00   mov ax,0   ax=0 ip指向1000:3

1000:3   e8 01 00   call s       pop ip ip指向1000:7

1000:6   40         inc ax

1000:7   58         s:pop ax                 ax=6


现在没搞懂的同学应该知道为什么是6了吧。

这只是我本人的理解,不知道是否正确,说错的地方望大家给我指正。如果正确也希望能帮助大家走出误区,解决检测点10.2这道题目,谢谢!

兰陵月 发表于 2016-12-15 12:46:20

本帖最后由 兰陵月 于 2016-12-15 13:04 编辑

"本人认为老师讲的将当前的ip压入栈中这样说不恰当,应该是IP的值先变成call指令后的第一个字节的地址,然后才被压入栈中。然而老师在讲后边call和ret指令时,又强调了ip指向了call下一条指令,再将ip入栈。"

你上述的理解是错误~CPU运行指令的步骤不知道你是否还记得,
CPU执行指令的步骤:
1、读入当前指令;
2、IP=IP+1
3、执行第1步已经读入的指令。

所以说当读入CALL指令那一行时,IP指针就已经自动指向了CALL的下面一条指令,因此执行CALL指令的时候,直接压入IP就是了,因为此时的IP就已经指向了下一条指令。

不知道解释得是否正确,请批评指正~~{:10_256:}

兰陵月 发表于 2016-12-15 12:52:19

下面的程序执行后,ax中的数值为多少?

内存地址    机器码      汇编指令   执行后情况

1000:0   b8 00 00   mov ax,0   ax=0 ip指向1000:3

1000:3   e8 01 00   call s       读入此指令时,IP偏移为6,将偏移6压入栈,转到标号s执行。

1000:6   40         inc ax

1000:7   58         s:pop ax         弹出栈,因为压入的是6,所以AX结果为6,因为没有RET指令,因此IP不会跳转到1000:6处执行,将会直接执行s:pop ax后面的语句,1000:6将被直接跳过。

王小2 发表于 2016-12-15 15:40:30

兰陵月 发表于 2016-12-15 12:52
下面的程序执行后,ax中的数值为多少?

内存地址    机器码      汇编指令   执行后情况


你2楼说的是正确的,但是3楼说的ip偏移地址为6,这里是错误的,老师讲过 e8 01 00 此处机器码的0001就是偏移地址,此偏移地址是由标号s处的地址(7)-call指令后的第一个字节地址(6)而得来的。   通过学习我是这样理解的

王小2 发表于 2016-12-15 15:48:05

兰陵月 发表于 2016-12-15 12:46
"本人认为老师讲的将当前的ip压入栈中这样说不恰当,应该是IP的值先变成call指令后的第一个字节的地址,然 ...

你说的这里我不太记得了,但是你说ip=ip+1,我觉得不应该加1,加的应该是这条指令的所占字节数,得出来的就是下条指令的地址,这样就和我说的是一样的了。按你说的ip+1,如果这条指令占3个字节,即使ip+1,得出来的还是在这条指令中的位置,这样cpu执行下条指令时就会出错

兰陵月 发表于 2016-12-16 09:47:59

王小2 发表于 2016-12-15 15:48
你说的这里我不太记得了,但是你说ip=ip+1,我觉得不应该加1,加的应该是这条指令的所占字节数,得出来的 ...

IP=IP+1的意思就是指向下一条指令的地址,不是纯粹的数字上+1,我是照书上解释的,请不要理解为IP+1就是IP+数字1~~{:10_262:}

兰陵月 发表于 2016-12-16 10:17:28

王小2 发表于 2016-12-15 15:40
你2楼说的是正确的,但是3楼说的ip偏移地址为6,这里是错误的,老师讲过 e8 01 00 此处机器码的0001就是 ...

e8 01 00,这个机器码的意思,你要反过来理解~

IP不是按照你这么推断的,你这是反推断IP结果值,你只要理解CPU的工作原理,就不难明白IP是怎么变化的了。
视频中小甲鱼的解释并没有错,但请仔细多听几次,他视频说到的那种推断是从另外一个角度来解释IP的变化的。

CPU加电启动后,就会永远按照CS:IP指向的地址一直不停执行下去,直到来到你编写的程序,然后就是下面顺序。
【这些图片来自王爽《汇编语言》(第2版)电子书第25页到第29页】










兰陵月 发表于 2016-12-16 10:33:48

本帖最后由 兰陵月 于 2016-12-16 13:04 编辑

所以按照上面图片中的解释:

内存地址    机器码      汇编指令   

................    .....................   ..............      
本处指令读取后执行前,CS:IP=1000:0000,本条执行执行完后,CPU执行CS:IP指向的指令
                                                         
1000:0   b8 00 00   mov ax,0   
1、读取b8 00 00,2、CS:IP=1000:0003,3、执行指令 mov ax,0


1000:3   e8 01 00   call s      
1、读取e8 01 00,2、CS:IP=1000:0006(IP=IP+本条指令长度即3,所以IP=3+3),3、执行call s
CALL S执行过程:①将当前的IP或CS和IP压入栈:当前IP=6,所以将6压入栈;②转移到S处执行。


1000:6   40         inc ax


1000:7   58         s:pop ax         
1、读取pop ax,2、CS:IP=1000:0008(此前经过CALL指令,IP的值已经变成了7);3、执行pop ax。
最后一条第2部为什么IP变成8,请详细阅读CALL指令的执行,里面解释了如何跳转,跳转的长度是多少,例如本例题中的短转移,标号S的值怎么来的,S实际上就是IP+0001,即6+1(这个6就是读取第2部指令完后IP的值,这个0001也就是e8 01 00的后两个字节),S在题目中代表跳转的偏移值,如果跳的更远,比如说跳到1000:8,则e8后面就应该是0200,即e8 02 00。

不知道这样解释,楼主是否清楚~~~
诶~这个蛋疼的排版,你将就着看吧~~

兰陵月 发表于 2016-12-16 12:52:07

本帖最后由 兰陵月 于 2016-12-16 12:58 编辑

关于JMP 后面相关标号的处理,CALL S后面跳转到S那一部分与JMP功能一样~~~请看下图~

小甲鱼同志的讲解应该是附录3里面的意思~

图片来自王爽《汇编语言》第2版电子书,附录3









王小2 发表于 2016-12-16 14:23:11

兰陵月 发表于 2016-12-16 12:52
关于JMP 后面相关标号的处理,CALL S后面跳转到S那一部分与JMP功能一样~~~请看下图~

小甲鱼同志的讲解应 ...

谢谢你啦,真是用心良苦啊{:5_100:}

兰陵月 发表于 2016-12-16 14:48:50

王小2 发表于 2016-12-16 14:23
谢谢你啦,真是用心良苦啊

这玩意必须得真懂,真明白,否则到后面越学越纠结,越来越看不懂~你懂了就好~,呵呵!

其实我回答你的问题,我也是一个复习的过程,我也得到了进步~~

一起进步~~{:10_332:}{:10_332:}

蛟龙入海 发表于 2017-8-22 14:01:48

兰陵月 发表于 2016-12-16 10:33
所以按照上面图片中的解释:

内存地址    机器码      汇编指令   


楼主这个很棒。
页: [1]
查看完整版本: 关于甲鱼老师讲的第十章call指令和检测点10.2的问题