|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 jueqingsizhe66 于 2011-3-21 22:14 编辑
《汇编语言》- 王爽 - 检测点10.5 - 详细解答
--------------------------------------------------------------------------------
检测点10.5(第183页)
----------------------
(1)答:ax中的数值为3
提示:不能利用T命令进行调试,则改用U和G命令来调试。可用U命令先查看指令"mov ax,4c00h"处的偏移地址,然后用G命令直接执行到指令"mov ax,4c00h"的偏移地址处。
准备进入call命令:
AX=0000 BX=0000 CX=0029 DX=0000 SP=0010 BP=0000 SI=0000 DI=0000
DS=14EE ES=14DE SS=14EE CS=14EF IP=000D NV UP EI PL NZ NA PO NC
14EF:000D FF160E00 CALL [000E] DS:000E=0E9B
-d ds:0
14EE:0000 00 00 00 00 00 00 00 00-00 00 0D 00 EF 14 (9B 0E) ................
14EE:0010 B8 EE 14 8E D0 BC 10 00-8E D8 B8 00 00 FF 16 0E ................
14EE:0020 00 40 40 40 B8 00 4C CD-21 00 00 00 00 00 00 00 .@@@..L.!.......
执行call命令后:
-t
AX=0000 BX=0000 CX=0029 DX=0000 SP=000E BP=0000 SI=0000 DI=000
DS=14EE ES=14DE SS=14EE CS=14EF IP=3302 NV UP EI PL NZ NA PO NC
14EF:3302 0000 ADD [BX+SI],AL DS
-d ds:0
14EE:0000 00 00 00 00 00 00 00 00-02 33 EF 14 9B 0E (11 00)
14EE:0010 B8 EE 14 8E D0 BC 10 00-8E D8 B8 00 00 FF 16 0E
14EE:0020 00 40 40 40 B8 00 4C CD-21 00 00 00 00 00 00 00
为什么会单步call执行之后IP值会出现那么大的区别 ip不是等于0吗? 不是要返回mov ax,stack的那个地方吗?
网上有这样解释:
首先IP进栈 此时IP的值是0011H不是0012H (连指令占多少个字节都数不清楚还在牛逼哄哄的),进栈后sp指针指到0EH ,然后进行JMP WORD PTR DS:[0eh]即将ds:[0eh]这个内存单元的地址赋给IP,又因为ds:[0eh]也就是ss:[0eh],所以程序又将0011赋给IP 即去执行了INC AX ,执行了三次 即AX=3
但是执行完call之后ip的值到底是怎样?以及为什么不能通过单步执行得到呢???????求解释!谢谢
补充:(1)CPU将call word ptr ds:[0EH]指令载入,IP指向call word ptr ds:[0EH]后的指令(inc ax),然后CPU执行call word ptr ds:[0EH]指令,,将当前的IP值(第一个inc ax指令的偏移地址)压栈,并将IP值改变为ds:[0EH]的值。
由于先压栈,所以ds:[0EH]=SS:[0EH]=17,call word ptr ds:[0EH]指令执行后IP=17
(2)inc ax运行3次后,ax=3
但是执行完call之后ip的值到底是怎样?以及为什么不能通过单步执行得到呢???????求解释!谢谢
诶这个挺有理的:
没有循环,直接下来了inc3次,刚开始(我也以为是个死循环.暴堆栈的操作.),分析很对,word call=1.push ip,2.jmp 地址.......原来地址为0,后来push ip后,地址=ip了,ip=下一条指令.所以等于没call.
要知道call执行了两个步骤:其中必须说明的是【当call送入指令缓冲器中ip已经加了,所以此时(call没执行时)ip是指向inc ax】
1:push ip
2:jmp word ptr ds:[0eH]
我觉得这是一种解释方法 也就是让我们觉得push 和jump是存在先后,也是课本上说的那样!
当然网上还有一种说法就是push 和jmp其实是同时双线开工的,我觉得也是有理
证据如下:
assume cs:codesg
stack segment
dw 8 dup (0)
stack ends
codesg segment
start: inc cx
mov ax,stack
mov ss,ax
mov sp,16
mov ds,ax
mov ax,0
call word ptr ds:[0eh]
inc ax
inc ax
inc ax
mov ax,4c00H
int 21H
codesg ends
end start
刚刚装载时:
AX=0000 BX=0000 CX=002B DX=0000 SP=0000
DS=14DE ES=14DE SS=14EE CS=14EF IP=0001
14EF:0001 B8EE14 MOV AX,14EE -------------CX=002B--------------------
而跳到mov ax,4c00h时:
AX=0003 BX=0000 CX=002C DX=0000 SP=00
DS=14EE ES=14DE SS=14EE CS=14EF IP=00
14EF:0015 B8004C MOV AX,4C00 -------------CX=002c---------------------
真的好像有在执行一遍inc cx!!!!!
{{{{{{{{那位哥们说:
1) 读入ss:[0e]=0, 把命令翻译成 call 0
2) push ip, sp=sp-2, ss[0e]=ip=12h
3) jmp 0
从头执行, sp=16, 第二次到call,
1) 读入ss:[0e]=12h 把命令翻译成 call 12h
2) push ip, sp=sp-2=000e, ss[0e]=ip=12h
3) jmp 12h
执行3个inc ax, 最后ax=3
所以第一次call后, 应该从头执行
个人觉得出现开始段被执行两次是因为现代CPU引入了流水线技术,call指令被分为push和jmp操作,在push ip执行后数据写入堆栈还未完成,CPU已经开始执行 jmp 指令,这时堆栈中的数据还没有被修改,仍为0,所以会跳转到程序开始段再次执行,再次执行到call指令此时push操作已经完成,就会跳转到inc ax执行下去}}}}}}}
我觉得也是挺有道理的!为了增加可信度 顺便再把inc bx放在inc cx之后 debug之后bx=0002而不是bx=0001也就是说应该是运行了两次吧!!
也就是说push 和jmp其实是同时执行的吧!!也许要知道这个,我觉得可以用时间来解决!去掉call语句然后得到一个程序的运行时间 然后加上call语句看两者的时间差!但是这个有点难于执行啊!!还不知道怎么计时啊!!希望有前辈指点下,即执行一条语句需要多少时刻????膜拜! |
|