导航: 老古网老古论坛XMOS公共讨论区XMOS开源项目区单片机程序设计嵌入式系统广告区域
→Keilc高手请指导: 下面是KeilC编译器错误,或者是我[guest]

 *第18295篇: Keilc高手请指导: 下面是KeilC编译器错误,或者是我理解错误?

  
楼 主:guest 2003年12月25日22:31
 Keilc高手请指导: 下面是KeilC编译器错误,或者是我理解错误?
/*编译器版本:   c51:6.23a */

/*编译参数
NOREGPARMS  不使用寄存器传参数
RET_XSTK    使用外部数据空间作堆栈
*/

unsigned char testpara(UINT8 pa1) reentrant
{
    unsigned char pa2;
    pa2=pa1*5+4;
    return  pa2;
}
/*在程序结尾有返回代码,反汇编为:
    -----------------------------------------------------------------
    MOV     DPTR,0x00YY     ;外部堆栈指针回缩
    LJMP    C?ADDXBP        ;外部堆栈回缩子程序
    -----------------------------------------------------------------
*/

unsigned char testpara1(UINT8 pa1) reentrant
{
/*
    在程序开始的地方有下面的代码:
    -----------------------------------------------------------------
    MOV     DPTR,0x00ZZ     ;外部堆栈指针增加
    LJMP    C?ADDXBPV       ;外部堆栈增加子程序,将sp处的返回
                            ;   地址填充到外部堆栈位置,并将XBP-2,
                            ;注:内部堆栈sp向上加,外部堆栈XBP向下减
    -----------------------------------------------------------------
*/
    unsigned char pa2;
    pa2=4;
    return  testpara(pa2);
}
/*在程序结尾有返回代码,反汇编为:
    -----------------------------------------------------------------
    MOV     DPTR,0x00YY     ;外部堆栈指针回缩
    CALL    C?ADDXBP        ;外部堆栈回缩子程序,
                            ;注意!!!!此处XBP(外部堆栈被缩回!!!!!!
                            ;外部堆栈放置的返回地址丢失!!!!!!
    LJMP    C?RET_XBP       ;从外部堆栈XBP中取出返回值,填充到SP中,
                            ;XBP-2,SP+2,但是取出的返回地址是错误的!!!
    -----------------------------------------------------------------
*/


void main(void)
{
    unsigned char pa1,pa2;
    pa1=5;
    pa2=testpara(pa1);  /*这一句可以正确返回*/

    pa2=testpara1(pa1); /*这一句不可以正确返回*/
}

/* 疑点 :
1.为什么testpara函数没有testpara1头部和尾部那样的语句生成?
2.RET_XSTK究竟代表什么含义?
3.如果我希望所有传递到参数都从XBP传递,但是返回地址在SP中定义,
  那该如何定义编译参数?
*/

QORSE
2003.12.25
QQ: 67897283
qorse@netease.com

  
2楼:rou_wexx 2003年12月25日23:15
 我想应该是你嵌套了一层子程序吧,而你的堆
我想应该是你嵌套了一层子程序吧,而你的堆栈又设在外部RAM,当有嵌套操作时就需要压栈咯。
我想C的函数的话默认就是以寄存器Rn规则来传递参数的要想实现你的想法,我是没试过。不好意思。
  
3楼:guest 2003年12月25日23:40
 FROM QORSE

感谢回帖!
FROM QORSE

感谢回帖!
需要说明的是,KEILC提供了返回地址在外部堆栈的方式,目的在于将返回地址放置到外部堆栈即XBP位置以节省硬件堆栈资源.但是按照它的生成代码方式,只有没有参数的函数才可以使用这种方式而不出错误.
现在的编译方式生成代码的顺序:
   1. 调用前,加大XBP以传递函数参数(如果参数长度为Len1,则XBP - Len1)
    2.CALL: 存PC返回地址到SP,SP+2,进入函数
    3.将XBP大小加大2,以存放返回地址.并将返回地址移到XBP,然后SP-2
    4.如果该函数有局部变量,则增加XBP以提供局部变量(如果局部变量长度为Len2则XBP - Len2).
    4.进行函数过程......
    5.一次缩回XBP,准备退出(如果有参数也一次缩回XBP即XBP + Len1 + Len2),问题就在这里)
    6.取回返回地址,放置到sp,使SP+2, 再缩回XBP,即XBP-2(XBP是对了,但是sp中错了)
所以C51.PDF帮助文档的P75的程序不会出问题!因为Len1=Len2=0!!!

按照一般的编译原则,或许下面的过程比较合理一些:
   1. 调用前,加大XBP以传递函数参数(如果参数长度为Len1,则XBP - Len1)
    2.CALL: 存PC返回地址到SP,SP+2,进入函数
    3.将XBP大小加大2,以存放返回地址.并将返回地址移到XBP,然后SP-2
    4.进行函数过程......
    5.缩回XBP(XBP + Len2)
    6.取出返回地址并放到SP,SP+2,然后缩回到XBP+2
    7.缩回XBP(XBP + Len1)
    8.RET

  
4楼:guest 2003年12月26日00:14
 更正说明错误:
1. 局部变量不放在外

更正说明错误:
1. 局部变量不放在外部堆栈中
2.xbp是局部变量的地址,而外部堆栈指针存放在BANK0:R6R7

但是程序结尾的 先缩回外部堆栈再取出返回地址放置到sp,应该是有问题的.


>>>>>>对该主题发表你的看法

本主题贴数4,分页: [第1页]


[上一篇主题]:哪里能找到keil c166 无限制版?

[下一篇主题]:请教高手:怎样用51系列单片机控制菲丽蒲的高频头??