汇编语言一有堆栈操作就出错,实在看不懂了

[复制链接]
查看11 | 回复3 | 2021-1-27 05:56:21 | 显示全部楼层 |阅读模式
RT
可以运行的是:
datasegment
bufdb00h,00h,00h,01h,01h,02h,03h,03h,00h,00h;定义内存的内容
;contequ$-buf
contdw10
;有能力的同学可以用buf1试试
buf1db00h,00h,00h,01h,01h,02h,03h,03h,00h,01h,02h,03h,01h,00h,02h;定义内存的内容
cont1equ$-buf1
dataends
stacksegmentstack'stack'
sapdb100dup(0)
topequlengthsap
stackends
maincodesegment
assumecs:maincode,ds:data,ss:stack
start:movax,data
movds,ax
movax,stack
movss,ax
movsp,100
movax,offsetbuf;buf的偏移量进栈
pushax
movax,cont;buf的个数进栈
pushax
movah,0
moval,00h;在调试时,把xx改为buf中的某个数
pushax;要查找的字符进栈
callsubproc;调用你写的子程序,显示xx在buf中的位置,有几个显示几次。
;例如查找00h时,应显示0、1和2,查找01h时,应显示3和4。
movah,4ch
int21h
subprocproc;子程序
;请填入代码
;popcx
;popdi
;popsi
movcl,03h
movsi,offsetbuf
movbp,0
movdi,offsetcont
for:
movdl,[si+bx]
cmpdl,cl
jnznext
movdx,bx
cmpdl,10
jbnum
adddl,7h
num:adddl,30h
movah,2
int21h
next:
incbx
cmpbx,[di]
jzexit
jmpfor
exit:
ret
subprocendp
maincodeends
endstart
但是,将subproc中注释掉的三个pop语句任意取消注释,就会因为堆栈错误使程序从头运行。。。。。
甚至。。。。
只要在subproc中写上
movax,stack
movss,ax
,就算还是把三个pop注释掉,只有这两个赋值操作都会有同样的问题。
呃。不知道我表达清楚了么,求各位解答,谢谢啦
分 -->
回复

使用道具 举报

千问 | 2021-1-27 05:56:21 | 显示全部楼层
你在子程的一开头就是几个pop?第一个pop不就将子程的返回地址给出栈了?子程最后的ret只能还怎么能返回到正确的地方?
如果是想获得子程的参数的话,可以使用下面的代码。另外参数压栈也是要进行平衡的,虽然你这代码调用子程后就结束了,没进行平衡也没有引发什么意外。movax,[sp+2];要查找的字符。[sp]是返回地址
movcx,[sp+4];buf的个数
movsi,[sp+6];buf的地址
;...
ret6;参数个数固定的,retn的平衡堆栈方法更合适

回复

使用道具 举报

千问 | 2021-1-27 05:56:21 | 显示全部楼层
修正下上面代码的实际编译时的错误:16位环境下sp是不能作为间接寻址寄存器的,可以参照高级语言的做法,利用bp来做:pushbp
movbp,sp
movax,[bp+2]
movcx,[bp+4]
movsi,[bp+6]
;...
popbp
ret6
回复

使用道具 举报

千问 | 2021-1-27 05:56:21 | 显示全部楼层
呃,不好意思,我基础比较差,所以再问问您。
呃,我刚按您说的,又试了一下,但是好像结果还是跟之前一样,乱跑。。。呃,您能再跟我解释一下么?
我用的是ret6,retn报语法错误,所以我又换成ret6了。
引用2楼zara的回复:修正下上面代码的实际编译时的错误:16位环境下sp是不能作为间接寻址寄存器的,可以参照高级语言的做法,利用bp来做:Assemblycode?12345678pushbpmovbp,spmovax,[bp+2]movcx,[bp+4]movsi,[bp+6];...popbpret6
……
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行