一个经典汇编问题:为什么DEBUG运行和直接运行结果不同

那个人的 2012-03-07 08:10:49
看,这个问题是如何的经典!
我在多家网站看到这个例题。截图上的说明突然让我凌乱了啊,有木有:


看吧:

.model small
.data
dw 8 dup(0)
.code
start:
mov ax, @data
mov ss,ax
mov sp,16
mov ds,ax
mov ax,0
call word ptr ds:[0eh]
mov ax,4c00h
int 21h
end start

程序直接运行,可以正常结束;
用debug调试,到call word ptr ds:[0eh]的地方,再单步执行一句,IP寄存器就莫名其妙的乱七八糟,怎么都回不到正常的IP了……
求解释。

其实程序正常结束是可以理解的,稍作分析就知道 ds:[0eh]的值恰好是 mov ax, 4c00h的地址,所以一个call把这个地址又放到了IP中,所以自然可以结束……但为什么debug调试IP就乱飞呢……求解释啊!
...全文
641 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
ProgrammingRing 2012-11-14
  • 打赏
  • 举报
回复
引用 9 楼 geekerxu2 的回复:
引用 7 楼 ProgrammingRing 的回复:引用 6 楼 ichijouziken 的回复:咕~~(╯﹏╰)b……我的问题是: 为什么直接运行没有错误,而DEBUG单步运行IP就乱飞…… LS能再说明白一点吗? call word ptr ds:[0eh]这句后,入栈ip地址,然后栈10h字节,所以就是call他下面那一句,至于debug里面会乱,……
bochs下跑了下,执行顺序确实是从头开始了一次,额,具体怎么搞的,现在不知啊……
geekerxu2 2012-11-09
  • 打赏
  • 举报
回复
引用 7 楼 ProgrammingRing 的回复:
引用 6 楼 ichijouziken 的回复:咕~~(╯﹏╰)b……我的问题是: 为什么直接运行没有错误,而DEBUG单步运行IP就乱飞…… LS能再说明白一点吗? call word ptr ds:[0eh]这句后,入栈ip地址,然后栈10h字节,所以就是call他下面那一句,至于debug里面会乱,那是因为没次单步debug都会保存现场,即把标志寄存器……
我Debug了一下,发现这个解释是不对的.虽然debug会保存现场,保存标志寄存器、cs、ip 但debug的保存地址是sp处(压栈的话保存地址是sp-2),也就是说这个过程并不会破坏我们栈内的数据. 在执行完call word ptr ds:[0eh] 这条语句之后查看内存发现 ds:[0eh]处的确保存有下一条语句的ip,sp=14也没错. 但是这条语句并没有如愿的跳到ds:[0eh]处数据所处的位置上. 然后我这样修改代码:
.model small
.data
dw 8 dup(0)
.code
start:
;添加下面3条语句
mov dl,'a'
mov ah,2
int 21h
mov ax, @data
mov ss,ax
mov sp,16
mov ds,ax
mov ax,0
;mov word ptr ds:[0eh],0017h
call word ptr ds:[0eh]
mov ah,7
int 21h
mov ah,4ch
int 21h
end start
就是在程序最开始的时候输出一个字符'a' 直接运行程序发现输出了两个'a' 这时候问题就很明白了. 老师上课讲过:段内间接转移,格式:CALL OPRD实现的过程是:
引用
SP-2=>SP;将堆栈指针SP减2 (SP)<=IP;将IP进栈 IP<=(OPRD);转到目的地址
但事实来看过程不是这样的,而应该是:
引用
TMP<=(OPRD);先把OPRD所指的数据读出来 SP-2=>SP;将堆栈指针SP减2 (SP)<=IP;将IP进栈 IP<=TMP;转到目的地址
(具体这个TMP是什么寄存器或者内存区域我还没搞清楚。。。) 这样就能解释上面所有的现象了: 直接运行时数据区的16个字节一直为0,ds:[0eh]也是0,第一次call语句的时候直接跳到了程序的开头(CS:0h),输出了第二个‘a’,并且ds:[0eh]被修改成call的下一条语句地址。于是第二次call的时候就正常跳到了call下一条语句。 而Debug的时候,ds:[0ah]到ds:[0fh]处被写入了ip、cs、标志寄存器(按顺序) 所以call语句的时候实际上就跳到了以标志寄存器数值为地址的语句去了,ip就飞了 (但是这个地方,执行完call之后的ip并不完全等于ds:[0eh],这个我还没搞懂。)
geekerxu2 2012-11-09
  • 打赏
  • 举报
回复
引用 7 楼 ProgrammingRing 的回复:
引用 6 楼 ichijouziken 的回复:咕~~(╯﹏╰)b……我的问题是: 为什么直接运行没有错误,而DEBUG单步运行IP就乱飞…… LS能再说明白一点吗? call word ptr ds:[0eh]这句后,入栈ip地址,然后栈10h字节,所以就是call他下面那一句,至于debug里面会乱,那是因为没次单步debug都会保存现场,即把标志寄存器……
thanx,那这种程序就没法调试了吗?~如果可以的话应该怎么调试啊?
ProgrammingRing 2012-03-08
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 programmingring 的回复:]

ds:0e怎么就是mov ax,4c00h了?你data段就申请了16个字节啊
[/Quote]
晕死,没看到栈也一个段……debug里会保存现场……会改栈的……
ProgrammingRing 2012-03-08
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 ichijouziken 的回复:]

咕~~(╯﹏╰)b……我的问题是:

为什么直接运行没有错误,而DEBUG单步运行IP就乱飞……

LS能再说明白一点吗?
[/Quote]
call word ptr ds:[0eh]这句后,入栈ip地址,然后栈10h字节,所以就是call他下面那一句,至于debug里面会乱,那是因为没次单步debug都会保存现场,即把标志寄存器、cs、ip入栈,比如栈的情况如下:

0 1 2 3 4 5 6 7 8 9 A B C D E F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -- 原始
调用call后:
0 1 2 3 4 5 6 7 8 9 A B C D E F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 0e 00 -- 假设mov ax, 4c00的地址是000e
但debug会把标志、cs、ip也入栈,栈顶就不是000e那个了,所以call的就是别地了,直接执行没这问题
那个人的 2012-03-08
  • 打赏
  • 举报
回复
咕~~(╯﹏╰)b……我的问题是:

为什么直接运行没有错误,而DEBUG单步运行IP就乱飞……

LS能再说明白一点吗?
ProgrammingRing 2012-03-07
  • 打赏
  • 举报
回复
ds:0e怎么就是mov ax,4c00h了?你data段就申请了16个字节啊
masmaster 2012-03-07
  • 打赏
  • 举报
回复
同上。。。
WJN92 2012-03-07
  • 打赏
  • 举报
回复
你什么时候把mov ax, 4c00h的地址放进去呢?
你还不如直接 JMP word ptr ds:[0eh] 呢
均陵鼠侠 2012-03-07
  • 打赏
  • 举报
回复
呵,调度程序用的是你程序的堆栈。当call指令执行时,互相干扰,就乱罗。。。

21,459

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧