leewon 发表于 2013-8-24 22:01:38

为什么这个代码非自然退出了

assume cs:codesg,ss:stacksg

stacksg segment
        dw 5,6,7,8
stacksg ends

codesg segment
        start :        mov ax,stacksg
                        mov ss,ax
                        mov sp,8
                       
                        mov ax,1
                        mov bx,2
                        mov cx,3
                        mov dx,4
                       
                        push ax
                        push bx
                        push cx
                        push dx;这条语句还未执行程序就退出来了
                       
                        pop dx
                        pop cx
                        pop bx
                        pop ax
                       
                        mov ax,4C00H
                        int 21h
                       
codesg ends

end start

调试结果:
---------------------------------------
c:\XJY\asm>debug 14.exe-t
AX=14F2BX=0000CX=0031DX=0000SP=0000BP=0000SI=0000DI=0000DS=14E2ES=14E2SS=14F2CS=14F3IP=0003   NV UP EI PL NZ NA PO NC14F3:0003 8ED0          MOV   SS,AX-t
AX=14F2BX=0000CX=0031DX=0000SP=0008BP=0000SI=0000DI=0000DS=14E2ES=14E2SS=14F2CS=14F3IP=0008   NV UP EI PL NZ NA PO NC14F3:0008 B80100      MOV   AX,0001-t
AX=0001BX=0000CX=0031DX=0000SP=0008BP=0000SI=0000DI=0000DS=14E2ES=14E2SS=14F2CS=14F3IP=000B   NV UP EI PL NZ NA PO NC14F3:000B BB0200      MOV   BX,0002-t
AX=0001BX=0002CX=0031DX=0000SP=0008BP=0000SI=0000DI=0000DS=14E2ES=14E2SS=14F2CS=14F3IP=000E   NV UP EI PL NZ NA PO NC14F3:000E B90300      MOV   CX,0003-t
AX=0001BX=0002CX=0003DX=0000SP=0008BP=0000SI=0000DI=0000DS=14E2ES=14E2SS=14F2CS=14F3IP=0011   NV UP EI PL NZ NA PO NC14F3:0011 BA0400      MOV   DX,0004-t
AX=0001BX=0002CX=0003DX=0004SP=0008BP=0000SI=0000DI=0000DS=14E2ES=14E2SS=14F2CS=14F3IP=0014   NV UP EI PL NZ NA PO NC14F3:0014 50            PUSH    AX-t
AX=0001BX=0002CX=0003DX=0004SP=0006BP=0000SI=0000DI=0000DS=14E2ES=14E2SS=14F2CS=14F3IP=0015   NV UP EI PL NZ NA PO NC14F3:0015 53            PUSH    BX-t
AX=0001BX=0002CX=0003DX=0004SP=0004BP=0000SI=0000DI=0000DS=14E2ES=14E2SS=14F2CS=14F3IP=0016   NV UP EI PL NZ NA PO NC14F3:0016 51            PUSH    CX-tc:\XJY\asm>


leewon 发表于 2013-8-24 22:05:52

同时,在调试过程中 mov sp,8 这条语句debug中也是不会显示的执行。

还有stacksg 赋初值是不是没有用啊,怎么查询内存 14f2:0处的值看不到5,6,7,8这几个数据啊?

AX=14F2BX=0000CX=0031DX=0000SP=0000BP=0000SI=0000DI=0000
DS=14E2ES=14E2SS=14F2CS=14F3IP=0003   NV UP EI PL NZ NA PO NC
14F3:0003 8ED0          MOV   SS,AX
-t

AX=14F2BX=0000CX=0031DX=0000SP=0008BP=0000SI=0000DI=0000
DS=14E2ES=14E2SS=14F2CS=14F3IP=0008   NV UP EI PL NZ NA PO NC
14F3:0008 B80100      MOV   AX,0001
-t

小咒 发表于 2013-8-25 10:18:22

测试栈内有代码被覆盖导出错,具体为什么会这样,我也不清楚

tsembrace 发表于 2013-8-25 10:45:19

你在1楼那代码里的注释是发现问题前还是后才加的?那注释符分号要用英文的。把注释符改下我试了是没有问题的,运行正常,结果也可以理解。

tsembrace 发表于 2013-8-25 10:54:58

至于你在2楼的问题:
1、单步调试t遇见mov ss,XX语句会自动把下一句一并执行
2、在debug把代码加载进去后你用d查看d ss:0 f是可以看到5678的,因为这时候还没有作为栈段。而当执行到mov ss,XX/mov sp,XX后已经将其设为栈段,并且逻辑上的栈在此时为空(也就是说系统可以把未用的栈空间作为它用),所以你这时候查看的话,该段可能就不是5678了。
一样的道理,到你4条push进去后你查看,是可以看到1234的,但4条pop后对应的栈空间又为空了,系统又可以拿作它用了,你就可能看不到1234了。

小咒 发表于 2013-8-25 12:08:12

tsembrace 发表于 2013-8-25 10:45 static/image/common/back.gif
你在1楼那代码里的注释是发现问题前还是后才加的?那注释符分号要用英文的。把注释符改下我试了是没有问题的 ...

我测试把注释去掉,执行到push cx的时候debug会报错,你那里不会报错么?

tsembrace 发表于 2013-8-25 12:38:42

小咒 发表于 2013-8-25 12:08 static/image/common/back.gif
我测试把注释去掉,执行到push cx的时候debug会报错,你那里不会报错么?

确实,直接g命令运行没问题,但单步的话到push cx就报错。
按实际想法,stacksg作为栈段,段空间大小为16字节,要使得该段作为栈段使用并且栈初始为空,在mov ss,ax后栈顶sp应设为10h.这样单步就没有问题。
这里面的原因我也不知道。

小咒 发表于 2013-8-25 13:01:57

tsembrace 发表于 2013-8-25 12:38 static/image/common/back.gif
确实,直接g命令运行没问题,但单步的话到push cx就报错。
按实际想法,stacksg作为栈段,段空间大小为1 ...

我debug的时候发现运行到push cx的时候栈内03地址u命令查看变成了push cx前面的话也有数据写入了,具体为什么这样我也没搞明白,如果dw 8 dup(0),sp指向10h的话确实没问题,其中的道理看来只能等高人来解答了

tsembrace 发表于 2013-8-25 13:27:17

小咒 发表于 2013-8-25 13:01 static/image/common/back.gif
我debug的时候发现运行到push cx的时候栈内03地址u命令查看变成了push cx前面的话也有数据写入了,具体为 ...

非但如此,你用debug加载,用g命令执行到4条push之后,再用d查看压入栈空间的数据,都是没有问题的(1234都是存放正确的)。
用g执行到最后,也是正常的(没有报错);只是这时候栈段已经空了,栈段数据可能发生了变化。
另外楼主这里stacksg段,虽然只定义了5,6,7,8四个字型数据,但实际分配给stacksg的空间也是16字节。
哪怕只是db 1这样的,至少都是分配16字节。
所以,对于这里,sp设为10h不是没问题,而就是“应该如此”。
当sp设为8后,按我们的想法,从stacksg段空间起始到栈顶还有8字节的空间,理论上在这里存放4字的数据是刚好,也没有问题的;我个人之前也是这么认为的。但单步调试就确实是报错了,是不是,栈段空间不能用足?要给他预留多些空间?但这又咋解释t和g分别调试的差异?

小咒 发表于 2013-8-25 14:09:30

tsembrace 发表于 2013-8-25 13:27 static/image/common/back.gif
非但如此,你用debug加载,用g命令执行到4条push之后,再用d查看压入栈空间的数据,都是没有问题的(1234 ...
确实如果小于16个字节的大小也会是16个字节
另外我把代码改了一下
assume cs:codesg,ss:stacksg

stacksg segment
      dw 8 dup(0)
stacksg ends

codesg segment
      start:       mov ax,stacksg
                        mov ss,ax
                        mov sp,10h
                     
                        mov ax,1
                        mov bx,2
                        mov di,3
                        mov dx,4
                        mov cx,2
                        
                        
                        s:push ax
                        push bx
                        push di
                        push dx;这条语句还未执行程序就退出来了
                        loop s单步调试,当第二次执行到push di的时候相同的也报错了,栈地址报错的地方是相同的,目前感觉我们只能认定为栈是需要预留空间的,以单步调试来说最起码要预留4个字节的空间?


tsembrace 发表于 2013-8-25 14:48:18

小咒 发表于 2013-8-25 14:09 static/image/common/back.gif
确实如果小于16个字节的大小也会是16个字节
另外我把代码改了一下
单步调试,当第二次执行到push di的时 ...

感觉上确实如此,你loop第一次到push dx的时候没有报错?因为那时候设定的栈空间还没有被push满。第二次到push dx的时候已经push8次,把栈弄满了,所以报错了?
你提到的“单步调试来说最起码...”这句对我是个核心语句,虽然无法得知确切的原因,但也大致可知,单步调试时候会利用设定的栈空间(即任何时候的ss:sp指向区域)保护该步骤时的某些数据?而g命令就不需要。

小咒 发表于 2013-8-25 15:03:45

tsembrace 发表于 2013-8-25 14:48 static/image/common/back.gif
感觉上确实如此,你loop第一次到push dx的时候没有报错?因为那时候设定的栈空间还没有被push满。第二次到 ...

不是,没有全部入栈就出错了,出错的位置和原本的代码相同,第二次di入栈就报错。

反正总结下来我们定义的16个字节的栈内会出现目前我们“未知的数据”而导致入栈出错,栈到底是否需要预留空间?想来想去以我目前的知识还是一个未知数吧,而另外发现一个问题就算我们直接以G命令可以顺利执行完毕后,定义的栈内还是会出现一些“未知的数据”

leewon 发表于 2013-8-26 01:43:48

感谢楼上的各位分析,仔细又看了下小甲鱼的第30集视频,段的大小必须为16的倍数,即最小必须为16.

但是如果sp没有设置为16的倍数会发生什么情况?跟踪了下代码,发现在mov ss,ax后,原来栈处的内容会被改写,具体情况见附件。
页: [1]
查看完整版本: 为什么这个代码非自然退出了