89C52堆栈的范围到底是低地址的128字节还是整个RAM?

2019-07-15 12:32发布

本帖最后由 dark_sky 于 2016-11-23 19:33 编辑

手头有个STC90C52的程序,keil C写的,修订版的上电几分钟就重启,没有用看门狗,排除了硬件掉电、数组或指针的越界操作,考虑是否堆栈溢出,手动更改了START51.A文件将STACK放在了DATA区,并将STACK长度定义为30H(子程序调用最大8层,开串口中断,串口中断调用一个非重入处理子函数,这个结构貌似不合理,但因为某些原因,只能这么搞,汗~~~),结果重启没有那么频繁了,大概半小时一次,这下要考虑重新排查数组指针越界了。
这里面有个问题,子程序调用压栈操作2字节PC指针,中断现场要再压栈7字节(这个芯片的DPTR有两组,所以多2字节)寄存器和2字节PC,算起来最多是:8*2(普通子程序)+7(反汇编中断的直接PUSH和POP指令,状态寄存器)+2(中断现场)+2(中断中的子程序)=27字节=0x1B字节,所以30H字节的STACK应该足够用。


好吧~~~这些都不是重点,重点是:STC的手册和Keil的手册上对51的STACk都是只要在RAM中就行,STC的手册中更是明确提出更建议在80H以后,也就是128~255地址的RAM;但在另外的文章里指出,系统的STACK应该是在7FH以下,因为POP和PUSH操作只能针对直接寻址单元操作,也就是低128字节,而高128字节则因为对应的直接寻址是SFR而不能用堆栈操作。而且貌似在多数的C51手册里 对0x00~0x7F地址RAM的说明里都有出现“大多数程序会把堆栈放在这以空间”的说法。那么问题来了~~~到底谁说的对?   
  还有——系统在子程序调用(ACALL、LCALL)和中断处理时的压栈和出栈操作我们不用去写PUSH和POP指令的(中断有部分需要),但是它是不是也和PUSH和POP完全一样,会不会用到不是直接寻址的单元,比如高128字节,只是它是内部操作,用别的办法代替了@Ri一类的间接寻址?

为此自己试验了下,在不更改STACK长度和位置时,重新编译下载,大约每2分钟重启,M51文件中看到的STACK位置是8EH,长度是1,当然后面都是GAP了,反汇编窗口看到的中断程序入口PUSH了7个字节,出口POP了7个字节。然后我更改STACK长度和位置定为DATA后,每30分钟随机左右重启,而且之前的工作中也遇到过编译后的程序占用data超过128字节时类似的问题,采用large模式后就正常了。所以一厢情愿的相信了STACK应该在低128字节,不知道对不对。
呵呵,所以又去请教了原厂的技术支持,得到的答案是用C的时候不要去管汇编,不要去动STACK或SP,keil会把一切搞的妥妥的.当然去除个人意见和对这位高手水准的猜测,我愿意相信他说的是对的,但仍然不知道到底STACK在高128字节时会不会出问题,好想弄清楚...


                           所以……高手们来a,谢谢不吝赐教^_^    ^_^   ^_^
~好吧,已经解决了,AT89C52 E文原版P6左上角有说明,堆栈本身实际就是间接寻址(用的SP寄存器),所以对于C52以后的片子来说0~256整个RAM空间都是可做为堆栈的。但PUSH和POP的源数据必须是直接寻址(这个指令里有说明)。至于别的,已经回复给了各位,等待论坛审核过了应该就可以看到了。
而如果说堆栈要放到80H以后是为了安全的话,个人觉得不如说是为了将80H前的留给更能发挥其作用的数据用,不过如果放到更低的地址,比如30H或者07H确实有可能因为别的数据可能是被分配在了堆栈后面的地址,比如将变量全局变量XX分配在了7DH,这样如果程序运行是的堆栈操作很多,可能最后导致栈顶SP指向了7DH,而在之后的堆栈操作比如函数调用时压栈PC将会改变XX的值,还可能因为改变XX值的操作而导致出栈时的PC值已经不是原先的值了(这是已经变为了XX改变后的值),这些都是不符合期望的。

问题已解决,是一个忘记的数组越界操作了。之前说的文章里有提到堆栈应操作应该是00~7FH是本人理解有误,其本意应该是在说PUSH和POP的操作数也就是源数据是00~7FH而不是堆栈地址应该在00~7FH。手册中所提到的多数程序将堆栈放在00~7FH也确有其事,但不是一定要放在这里。







友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
19条回答
HARRY007
1楼-- · 2019-07-17 08:13
 精彩回答 2  元偷偷看……
HARRY007
2楼-- · 2019-07-17 09:11
dark_sky 发表于 2016-11-23 18:00
@HARRY007  弄好了,是一个预留给升级用的数组越界了

恭喜恭喜。
我觉得论坛里的这个帖子讲的很好
http://bbs.elecfans.com/jishu_412923_1_1.html
dark_sky
3楼-- · 2019-07-17 10:07
@HARRY007 嗯,以前也有过数组越界或者指针越界导致数据莫名其妙的变化或者重启的,这次这个确实没想到,开始就排查了可能的越界操作,呵呵,最后还是没想到是这个认为基本都忘了的数组,到一步步注释掉所有的过程和函数,注释到这个过程所在的子程序里发现就没有重启了,于是给计数器变量复位成0,一切OK。才想到这里还有个数组,呵呵。
之前因为硬件限制,这个程序的结构搞的比较复杂,中断里还有些嵌套过程,所以在第一遍排查过越界操作后就怀疑堆栈了,尤其是改了堆栈地址以后重启频率还明显有改善,加上之前确实遇到过复杂程序堆栈搞到很大还溢出,所以就先靠堆栈来了,不过计算了嵌套层数和中断后把堆栈长度做到48字节还是重启……于是反过来再排查越界,还是忽略了这个数组,呵呵,
上官梦舞
4楼-- · 2019-07-17 11:54
128低的还有128高的,stack用C的话自动分配,不用管。
805570
5楼-- · 2019-07-17 15:24
还有做广告的?
dark_sky
6楼-- · 2019-07-17 20:18
 精彩回答 2  元偷偷看……

一周热门 更多>