关于可重入函数(可再入函数)和模拟堆栈(仿真堆栈)
,2,3,4);
MOV
LCALL
;指向0xFFFF
MOV
MOVX
MOV
MOV
MOV
LCALL
MOV
;并存储在外部数据存储器0x0000和0x0001处
;(int型为两个字节)
MOV
MOVX
INC
MOV
MOVX
}
RET
说明:模拟栈指针最初在startup.a51中初始化为0xFFFF+1;由以上汇编代码可以看出参数是从右往左扫描的。
接下来看看fun的汇编代码:(很长,大家耐心看吧,有些可以跳过的)
C:0003
MOV
LCALL
MOV
MOVX
MOV
LCALL
MOV
MOVX
MOV
LCALL
MOV
MOVX
MOV
LCALL
;局部int变量做准备
j1 = a + b + c +d;
MOV
LCALL
;一个参数,此时DPTR=0xFFFF
;注意:C?XBPOFF不改变C?XBP的值
MOVX
MOV
MOV
。。。。。。
。。。。。。;省略,完成取参数2,取参数3,取参数4并相加
。。。。。。
MOV
MOV
MOV
MOVX
INC
MOV
MOVX
。。。。。。
。。。。。。
。。。。。。;省略,完成j2=j1+10,并把计算结果j1压入模拟栈
return j2;
MOV
MOV
INC
INC
MOVX
MOV
INC
MOVX
MOV
}
MOV
LCALL
RET
说明:模拟栈结构如下
参数4 |
参数3 |
参数2 |
参数1 |
j1低字节 |
j1高字节 |
J2低字节 |
J2高字节 |
接下来说明两个重点子函数C_ADDXBP和C_XBPOFF
MOV
ADD
MOV
MOV
ADDC
MOV
CJNE
MOV
RET
C:00B9
JBC
MOV
;的模拟栈指针赋给C_XBP
MOV
RET
C:00C2
MOV
MOV
SETB
RET
MOV
ADD
MOV
MOV
ADDC
MOV
RET
终于到尾声了,最后重点说明啦~~~
模拟堆栈是向下生长的,C_XBP最初等于0xffff+1,那么请看下面这句
MOV
LCALL
(0xffff+1)+0xffff = 0xffff
即C_XBP -1;
再看
MOV
LCALL
即C_XBP-2
再看
MOV
LCALL
即C_XBP-3
。。。
其实是这样:加0xffff相当与减1,加0xfffe相当与减2,加0xfffd相当于减4。。。。。。为啥,就不用说了吧:)
结束语:
经过了几天的研究,终于写了个总结报告,算是自己的一点小小成就吧,错误之处在所难免,希望能够同大家一起讨论问题,共同进步。
参考文献:
1、徐爱钧,彭秀华 《单片机高级语言C51windows环境编程与应用》电子工业出版社2001
2、彭光红,构造一个51单片机的实时操作系统。
附录:
在其它环境下(比如PC,比如ARM),函数重入的问题一般不是要特别注意的问题.只要你没有使用static变量,或者指向static变量的指针,一般情况下,函数自然而然地就是可重入的.
但C51不一样,如果你不特别设计你的函数,它就是不可重入的.
引起这个差别的原因在于:一般的C编译器(或者更确切点地说:基于一般的处理器上的C编译器),其函数的局部变量是存放于堆栈中的,而C51是存放于一个可覆盖的(数据)段中的.
至于C51这样做的原因,不是象有些人说的那样,为了节约内存.事实上,这样
可重入函数模拟堆 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)