他说的没错的,不过他关于IP的说法其实我个人感觉描述的不太准确
他讲CS和IP的时候将这个过程分为了3步骤:
1、从CS:IP指向的内存单位读取指令,读取的指令进入指令缓冲器
2、IP=IP+指令长度,从而指向下一条指令
3、执行指令,转到1
我当时看这个直接懵逼了,后来看jump详细的懵逼了半天,但是你会发现所有指令的说明他都用了一句很严格的“当前IP值”,然后我懂了
不过我觉得还是不太准确,我觉得应该分为4步:
1、从CS:IP指向的内存单位读取指令,读取的指令进入指令缓冲器
2、IP=IP+指令长度,从而指向该指令的下一条指令
3、执行指令,如果该指令修改CS和IP,对CS和IP进行第二次计算
4、通过计算的CS和IP值,指向真正要执行的下一条指令
有什么区别,当然有!
书中经常提到一个当前IP值,以及调试,调试我们理解的就是执行前和执行后
其中他所谓的当前IP值是指代的我说的第2个,也是他说的第2个,但是我们新人想象中的执行前就是所谓的第1步,甚至都没有IP=IP+指令长度 的意识,毕竟调试前不就代表没执行吗,没执行那IP当然就是指向该代码的值(没加指令长度的IP值),从而造成误解
而执行指令后,如果指令修改了IP和CS(比如说jump),这个时候又进行了一次计算,而调试步入实际执行到了我说的第4步,也就是他说的第3步,然而我们新人又会忽略JUMP这类指令的计算方式,毕竟涉及到一个偏移值,也懒得算。造成第二次误解
但是更有意思的是,即使我们误解了2次,并不影响我们观看指令的运行,因为你误解错了,你会发现最后CS和IP计算的地址和没误解一样,但是如果涉及到IP值这个数据的时候,就会发现自己突然就看不懂了。不如jump的那个偏移值,我记得之前有个监测点,说的是个奇怪的程序,里面就说到那个偏移是-10=F0,我当时算了半天明明是8而不是10,那就是因为我忽略了那个代码的长度2,而且王爽老师说的当前IP值就是我算出来的8加上这个长度
同样的,楼主这个问题,也是这个问题,你这个时候IP值是B,然后这个代码的机器码是E8 01 00,对应的长度是3,那么问题来了,你调试前CS和IP指向这条代码,IP=B
然后执行代码之前会进行计算IP=IP+指令长度3,这个时候IP=E,而这个时候的IP值才是王爽老师说的当时的IP值,再然后执行CALL,CALL会把这个IP=E入栈,所以栈顶的值就是E而不是B,再然后你CALL之后跳转IP会再次计算IP=B+指令长度(3)+偏移;而偏移=目标地址-当时IP=目标地址-(执行前IP值(B)+指令长度),所以计算出来的IP=目标地址。
如果你不信的话你可以计算的,这段代码不是有个CALL吗,对应的机器码是E8 01 00,这个E8应该就是CALL,而后面的数据就是偏移值,而这个偏移值=目标地址-(B+3)而不是
目标地址-B,也就是说你这段代码跳转到的目的地=0001(倒序的)+B+3=0F
也就是对应的POP AX
也就是说你CALL相联系的就是
CALL S
S:POP AX
这个应该是笔误,call压栈操作是压入的下一条指令的IP地址,即call指令的返回的IP地址