首页
社区
课程
招聘
求助:代码错的问题是什么
发表于: 2009-12-7 13:29 6806

求助:代码错的问题是什么

2009-12-7 13:29
6806
assume cs:codesg  
codesg segment  
  dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h  
  dw 0h,0h  
  start:  
  mov ax,cs  
  mov ss,ax  
  mov sp,12h  
  mov ax,0  
  mov ds,ax  
  mov bx,0  
  mov cx,8  
s:  
  push [bx]  
  pop cs:[bx]  
  add bx,2  
  loop s  
   
  mov ax,4c00h  
  int 21h  
codesg ends  
end start      
这是错误的           

assume cs:codesg  
codesg segment  
  dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h  
  dw 0h,0h  
  start:  
  mov ax,cs  
  mov ss,ax  
  mov sp,1ah  
  mov ax,0  
  mov ds,ax  
  mov bx,0  
  mov cx,8  
s:  
  push [bx]  
  pop cs:[bx]  
  add bx,2  
  loop s  
   
  mov ax,4c00h  
  int 21h  
codesg ends  
end start      
这是正确的,  
问题是:用内存0:0~0:f中的内容覆盖程序中的数据

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (25)
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好像是什么用了堆栈,但不知道是什么?求高手给出原因
2009-12-7 13:39
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
看7楼吧,刚才明显说错了。
2009-12-7 13:47
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
我已经试了至少得是18h
2009-12-7 13:52
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mov ax,4c00h
int 21h


会不会占用堆栈空间呢?

查了下。起码有不少中断是使用堆栈的。
2009-12-7 14:04
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我用debug调试,这两句没有执行前,就开始占用堆栈了,
好像是
  mov ss,ax  
   mov sp,1ah
这两句一运行堆栈里就有一些寄存器数据被 保存到里面了。
2009-12-7 14:12
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
多亏楼主提醒。我在3楼的回答明显错了。后面2x2那个2只占用内存空间,不占用堆栈空间的,不需要加上去。
18h(=24h)  >=  2+8x2+3x2

红色2不知道哪里来的,求指教。
后面3x2是因为 int N这样的有中断类型码的中断。执行的时候都要有如下操作:
(1)取得中断类型码N
(2)pushf
(3)TF=0 , IF=0
(4)push CS
(5)push  IP
(6)IP=(N*4),CS=(N*4+2)
其中2、4、5步骤执行完毕需要3个堆栈空间
2009-12-7 14:25
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
刚开始学习汇编,还没学到中断,你说的中断内容有点看不懂,但我调试的时候,好像我的程序在内存的地址前面几个地址好像就是你说的中断占的那么多空间。
2009-12-7 14:32
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
没听明白,你截图发给大家看看吧。

PS:16位汇编只看过,没动手写过,我也是纸上谈兵,说错勿怪。
2009-12-7 14:35
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
为什么mov ss,ax要分配一个堆栈空间来执行
2009-12-7 14:38
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
我在办公室,不方便
2009-12-7 14:39
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
总之一句话,你说的是对的了
2009-12-7 14:40
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
here is NULL
2009-12-7 14:45
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
那,mov ss,ax执行后不是要把 dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h  
  dw 0h,0h 压栈吗,不要累加器eax吗???
2009-12-7 14:55
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
还是看雪的人厉害,在csdn等了几天也没说出个所以然来,也不知道是不是人家闲问题太简单不愿意回答
2009-12-7 15:00
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
晕,
mov ax,cs
  mov ss,ax  
  mov sp,12h

红色标记代码被我忽略了,理解岔了,

原来是我胡说八道。。
2009-12-7 15:03
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
楼主,你是执行出错还是编译出错。
SS和CS同段,按说用不到那么大的空间。
完全不懂,求高手指教。
现在时间有点紧,夜晚帮你想想吧。
2009-12-7 15:15
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
执行和编译都通过了,是最终结果错了,就是不知道为什么要用那么大的空间。我觉得你说的中断很有道理,虽然我没学到中断。
你忙,有时间再想想。
2009-12-7 15:19
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
我已经试了至少得是18h

麻烦楼主再测试下16h。想不出哪里必须需要1个空间。
2009-12-7 21:04
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
20
楼主和我刚才一样,使用debug去调试16位程序,那么其实我想知道,楼主说的“最终结果错了”是指在哪个地方,用什么手段,来检测最终结果,从而知道它错了?从而,你所要求的“正确结果”,到底是在什么时候保持这个结果,就算正确呢?比如,是在调用int 21h退出之前?如果你想不清楚这一点,不理解这有什么重要,那么看下面我说的内容,你可能会晕掉。

我用debug调了一下,发现7楼说的是有道理的,除了那3x2字节很明显之外,另外的2个字节,应该是中断处理程序在堆栈进行push和pop的时候修改掉的(比如进入中断处理程序后就push bp,返回之前pop bp)。

但是到了这里,当我考虑为什么会有中断介入其中时,我才发现原来自己陷入了一个陷阱,就是我上面提问的:“你在什么时候,用什么方式来检测内存中的内容,这个检测操作本身会不会导致内存内容被修改,从而反而影响了程序的结果?

显然,如果单独从这个程序的流程看来,只有最后INT 21h这个程序退出的中断引起的压栈操作,会导致覆盖掉我们想修改的地址。但是,由于这里本来就是要退出的(既然程序马上要退出了,退出之后本来就不能再操作这个区域,那么这个地方在退出时是否被修改已经不再重要),因此,如果我们以“在INT 21h被调用之前程序确实把0000:0000~0000:000F这部分内存内容复制到了cs:0000~cs:000F”作为程序是否成功的判断标准,那么,因为在程序执行起来之后用int 21h退出之前没有调用其他中断,那么它应该是成功的。

但是为什么我们观察不到这个成功的结果呢?或者说为什么我们观察到的是不成功的结果呢?你和我一样使用debug来单步调试和观察,那么原因就是“我们为了观察这个结果所作的操作,影响了这个结果本身”。

因此,如果我想的没错,这是一个debug.exe调试16位程序出现的“海森堡效应”(《软件调试》中借用这个量子力学名词来指代因为调试器的介入而对程序流程造成的影响)。

我没有记错的话,debug.exe的调试代码和被调试代码,两者处于同一线程环境中,使用同一堆栈。这样的问题是,当我们在debug.exe里需要观察它是否正确写入了内存数据的时候,我们往往采用单步的方式,而实现这个单步的原理,导致程序每走一个命令,都会额外地触发一次单步的中断。而恰恰是当进入单步中断的时候,执行了7楼所说的压栈操作,从而破坏了SP上的数据。

也就是说,如果我们不用单步操作去观察它的时候,你只是mov sp,12h是没有问题可以保证在int 21h被调用前把0000:0000~0000:000F这部分内存内容复制到cs:0000~cs:000F(直到int 21h调用使它被修改)。然而,如果我们去单步它,我们的单步操作(导致额外执行单步中断时的压栈操作)反而破坏了相应数据,从而使得我们必须把这个12h改大才能保证在单步时该处数据的安全。这也就是为什么单步时还没有到int 21h的位置,却已经发现数据不对了。

为了证实我的推论,我将程序作如下修改:
.8086
assume cs:codesg
codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
dw 0h,0h
start:
mov ax,cs
mov ss,ax
mov sp,12h
mov ax,0
mov ds,ax
mov bx,0
mov cx,8
s:
push [bx]
pop cs:[bx]
add bx,2
loop s
mov sp,1ah
int 3
mov ax,4c00h
int 21h
codesg ends
end start

如上,我在对内存内容进行复制之前,把sp仍定为12h,然后在内存内容复制完毕后加了个int 3指令,这样我不需要一直单步而只需要按一下g运行起来,就可以在int 3指令前断下,从而避免在内存内容复制过程中单步造成的破坏。只要在内存内容复制完毕后,在执行int 3指令之前,把sp再调大,就可以避免后面的int 3指令破坏已经复制好的数据。只要我在这个int 3指令导致debug自动断下的时候,检测复制的内存内容,确认其无误,就可以说明在内存内容复制过程中用mov sp,12h是完全可以的,更可以说明debug时数据出错完全是额外的单步造成的结果。

结果如下:

-g

AX=0000 BX=0010 CX=0000 DX=0000 SP=001A BP=0000 SI=0000 DI=0000
DS=0000 ES=13D2 SS=13E2 CS=13E2 IP=0033 NV UP EI PL NZ AC PO NC
13E2:0033 CC INT 3
-d 0000:0 0F
0000:0000 68 10 A7 00 BB 13 E3 0D-16 00 9A 03 B1 13 E3 0D h...............
-d cs:0 0F
13E2:0000 68 10 A7 00 BB 13 E3 0D-16 00 9A 03 B1 13 E3 0D h...............

结果如我所料,只要我们不去用单步来干预程序的流程,即使只是mov sp,12h,程序也完全可以正常复制内存内容,直到一个中断操作破坏它(在原程序中是直到int 21h才破坏),但是如果我们单步,那么复制内存的操作完成之前,前面复制的数据就被我们通过debug额外引入的单步中断给破坏了。

还要提到的是,如果在g之前先查执行-d 0000:0 0F,会发现跟g一次之后再查看的内容不一样,也就是说在执行过程中,其实0000:0000~0000:000F的内容也不是一直静止不变的。

调试器的“海森堡效应”通常是比较头疼的,程序员调试程序结果不对考虑原因时,这也是容易忽略的死角。如果楼主一下子没明白我在说什么,请怀特迈恩给他补充说明解释,我睡觉去了……
2009-12-8 04:35
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
额,简单说下,我的看法:
以你最开始出错的程序为例,
(1)如果源程序后面没有
mov ax,4c00h
int 21h

那只需要12h(>=8x2+2)就行了。(后面的那个2就是指push [bx]  pop cs:[bx]所需要的一个堆栈空间)

(2)如果源程序后面有
mov ax,4c00h
int 21h

那么只需要16h(>=8X2+2+3x2-2).(3X2见我7楼的解释,就是调用此类中断时要用到的3个堆栈。为什么最后减去个2是因为,前面那个2所需要的堆栈空间被(中断)重复利用了当然要减去了)

(3)如果你要调试你的源代码并保证正确时,那你需要16h+2h(中断后观察)或者12h+2h(中断前观察)的堆栈空间。如小聪大大解释的16位单步调试“海森堡效应”这个原因,单步调试应该保证随时堆栈多出1个空间 以 保证单步调试不修改源程序。(如果不多出1个空间,未必错误但是会很可能出错。例:本程序就悲剧了,因为用到push [bx]  pop cs:[bx](当bx=14时))  如何分析并验证此类错误,请仔细看小聪大大在LS给大家的演示。

以上是学习了20楼后的一些小结:本人没有16位汇编编码经验,如有错误,请大家指正。

PS:Kx别给我,都给20楼,我2次理解错误,惭愧中
2009-12-8 08:49
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
没功劳也有苦劳啊,其实我昨天想了一晚上,也想到了是不是debug调试出的问题,但是不知道该如何防止debug中断影响,也不知道用什么命令,必定刚开始学吗
可以结贴了,谢谢两位的大力帮助。
2009-12-8 09:37
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
又追加了10kx,谢谢了,我什么时候也能领赏啊???唉。。。。。。。
2009-12-8 09:44
0
雪    币: 444
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
我什么时候也能领赏啊???

有的人的问题也蛮简单的,反正我动不动刷新,争取第一时间回贴。
不过,80%的话题一点都不懂,哎

高手都不抢kx,只解决问题,不象我还没脱离QQ斗地主“小地主”称号这样的诱惑,越没什么墨水越想显摆,恩,我是乡下人。
2009-12-8 10:09
0
雪    币: 158
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
在看雪里,我99%都回答不了,呵呵,除非是跟技术无关的能回答
2009-12-8 10:52
0
游客
登录 | 注册 方可回帖
返回
//