最近,在用keil 写一个小程序时,想实践一下从汇编调用 C语言函数,我们都知道C语言调用汇编函数讨论得较多,但反过来,从汇编中调用C语言的函数未见深入分析;在开始的时候,还是忽视了一个问题,就是对现场的保护和还原,以导于程序跑飞。
下面的一个小的测试用例,主要作用是:从C语言程序中调用一个用汇编写的名为int LEDFLASH(int a, int b)。并从该汇编函数中,反过来调言用C语言实现的delay()延时程序。最后的结果是:由P2口控制的LED灯出现闪烁的现象。
C语言源程序所在文件名为:user.c,C语言源程序如下:
#include <reg52.h>
void delay(int,int);
int LEDFLASH(int a,int b);
void test();
void main()
{
P2 = 0xff;
while(1)
LEDFLASH(0xff00,0x0007);
}
void delay(int a,int b)
{
int i,j;
for(i = 0;i<a;i++)
for(j= 0;j<b;j++)
;
}
void test()
{
delay(200,245);
P2 = ~P2;
delay(201,300);
}
/***************************/
下面是名为afun.asm 的文件,其中实现对LED灯的控制和反调C语言函数。
Name TEST1
EXTRN CODE(_delay)
?PR?LEDFLASHC?XY SEGMENT CODE
PUBLIC _LEDFLASH
RSEG ?PR?LEDFLASHC?XY
using 0
_LEDFLASH:
mov a,r7
add a,r5
mov r7,a
mov a,r6
add a,r4 ;接收参数并计算
mov r2,ar7
mov r1,a ;保存计算结果
push ar7
push ar6
push ar5
push ar4
push ar3
push ar2
push ar1
push ar0 ;保护现场
mov r7,#200
mov r6,#0
mov r5,#200
mov r4,#0 ;传递延时参数
call _delay ;调用C语言写的延时函数
pop ar0
pop ar1
pop ar2
pop ar3
pop ar4
pop ar5
pop ar6
pop ar7 ;还原现场
mov P2,r2
push ar7
push ar6
push ar5
push ar4
push ar3
push ar2
push ar1
push ar0
mov r7,#200
mov r6,#0
mov r5,#200
mov r4,#0
call _delay
pop ar0
pop ar1
pop ar2
pop ar3
pop ar4
pop ar5
pop ar6
pop ar7
mov a,r2
cpl a
mov P2, a
;MOV P1,r1
RET
END
以上汇编函数中调用C语言函数容易被忽视的地方是在调用(call _delay)时,往往容易遗漏对现场的保护,即对CPU寄存器的保护;在汇编调用C语言实现的delay(int,int)函数前,先对cpu的寄存器进行入栈,调用完后,再进行出栈还原现场。这是因为从汇编调用C语言函数时,C语言函数没有替汇编完成该汇编函数要用到的寄存器(含状态寄存器)等的保护。如果不注意这点,写出来的程序将出现意外。上面例的代码还可以优化,由于只是做一个测试,未进行优化。 在网上也会看到其它少量的讨论从汇编调用C语言函数的文章,还未见有对寄存器进行保护和还原的。