8086汇编 栈出错问题 错误: NTVDM cpu 遇到无效指令 cs:0000 ip:0077 op:f0 37 05 10 02
我看的是王爽老师的 < <汇编语言> >
其中有段栈程序:
assume cs:codesg
codesg segment
mov ax,2000h
mov ss,ax
mov sp,0
add sp,4
pop ax
pop bx
push ax
push bx
pop ax
pop bx
mov ax,4c00h
int 21h
codesg ends
end
一运行就有这个错误:
NTVDM cpu 遇到无效指令 cs:0000 ip:0077 op:f0 37 05 10 02
希望大家帮个忙,谢谢!
[解决办法]
已经有100+人问这个问题了,try to:
add sp,4 -> add sp,16
[解决办法]
这个程序是个有问题的程序,它是个逻辑上的程序,不会出现编译问题,但在CPU上执行肯定会出问题。具体解释如下:
mov ax,2000h
mov ss,ax
mov sp,0
程序没有定义堆栈段,而是通过mov ss,ax指令定义了堆栈段的基地址,这种定义堆栈段的方法叫做硬性编码,但到这里还没有暴露出硬性编码的bug,堆栈段在内存中的基地址是20000H。mov sp,0指令把堆栈指针设置到了堆栈顶部,在内存的00000H处,这个区域不是一般的应用程序可以修改的,不能作为堆栈使用,00000h~000FFH是中断向量表的所在地,这个地方从理论上是只读的,并应该随意向这里写东西。但程序执行到这里,既没有读,也没有写内容,仍然没有引爆错误。接下来:
add sp,4
pop ax
pop bx
add sp,4,设置了堆栈指针的位置,没问题,但是设置的不是地方。
pop ax
pop bx
上面两条指令是读取00002H和00000H处的内容,没错的。
push ax
push bx
上面两句修改了中断向量表,中断向量表的0 号(除法错中断)中断都是非常重要的,
注意了,pop ax pop bx和push ax push bx不对应,调换了0000 和0002两个字单元的内容,也就是说错误的写了中断向量表的0号中断的内容,后面在调用int 21中断的时候,可能是CPU或者NTVDM cpu检测到了0号中断向量入口地址被错误的修改了,引发了错误。
解决办法:将
push ax
push bx
改为:
push bx
push ax
就是将读取的数据,原样的写回去,这就没事了。
[解决办法]
我刚才的解释有些错误,上面的程序虽然修改了中断向量表的0号中断的入口地址,但是只有在调用0号中断时才会出现错误。上面的程序段我在XP2的ntvdm下已经通过,想必楼主不是在“开始-> 运行-> CMD-> debug”下运行的,估计是在Windows下的一些汇编编译器下运行的,这些编译器和windows提供的debug并不能完全等价,更不能与DOS下的debug等价,这些编译软件提供的环境都很不真实,模拟出来的DOS环境都很不完善,所以出现上面的错误是编译器的原因,也是必然的。虽然是编译器的原因造成的上面的错误,但不能不提的是上面的程序风格不雅,如果不是编写操作系统的话,尽量不要用硬性编码,就是不要出现诸如:mov ss,ax mov sp,0 add sp,4 这样直接给段寄存器或指针寄存器赋值和修改堆栈寄存器指针的语句,需要堆栈时用一个“.stack”伪指令不更好吗?
推荐一个Windows下的汇编编译器:Masm for Windows 6.0,这个编译器在一直更新,功能也在日渐完善,而且是免费的,建议大家使用。
[解决办法]
应该分配一个堆栈。
[解决办法]
纠正我在上面所犯的错误(再论堆栈段的实现形式):
mov ax,2000h
mov ss,ax
mov sp,0
前两句设置堆栈段的基地址,使SS指向内存的20000H处。就是说将栈底设置为20000H。
SP是堆栈指针,它时刻指向栈顶。SP的初始值0表示堆栈段的大小。因此上面的三条指令的意义就是:在内存的20000H处设置了一个大小为0堆栈,栈底,栈顶,都指向这里。
add sp,4 重设堆栈段大小,将堆栈段设置为4个字节大小。
[解决办法]
如果我没记错,这个应该是NTVDM的BUG
直接无视吧
[解决办法]
在DEBUG下直接输入:
-a 100
mov ax,2000h
mov ss,ax
mov sp,0
add sp,4
pop ax
pop bx
push ax
push bx
pop ax
pop bx
mov ax,4c00h
int 21h
进行调试,试试!应该不会出错^_^!我试过好几次都正确无误!