在keil中,汇编函数可以使用如下的方式来定义一个汇编函数
__asm void SVC_Handler(void)
{
extern CurrentTask;
PRESERVE8
ldr r3, =CurrentTask
ldr r1, [r3]
ldr r0, [r1]
ldmia r0!, {r4-r11}
msr psp,r0
isb
mov r0,#0
msr basepri,r0
orr r14,#0xd
bx r14
}
这个函数在ARMCC中编译的时候是不会报错的,但是在使用ARM GCC的时候,这种定义方式会报出类似如下的错误:
../project/src/cx_task.c:54:9: error: stray '#' in program
54 | mov r0,#0
也就是这些符号编译器无法识别,__asm void func(void)中的__asm也无法识别。我们参照cmsis_gcc.h中操作PSP指针的一个函数来看看在GNU里面要如何进行操作。
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack)
{
__ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : );
}
可以看到在这里使用的是内联汇编的形式,__ASM 其实就是asm,是一个宏,asm内联汇编的用法是这样的:
asm(
"asm1\n"
"asm2\n");
或者就是像cmsis_gcc.h这样子用:隔开每一个asm字符串。
那么这里要清楚一个就是问什么我们的汇编函数需要加上__asm在函数定义开头。这里就要区分我们一般的普通函数在编译的时候是会有标准的压栈lr的过程,但是对于我们这种不存在层级调用的函数而言这么做会浪费数个周期的时间,因此需要把函数设置为裸函数或者内联函数,方式有两种:
// Methon1:
__attribute__((always_inline)) void func(void){
// function code
}
// Methon2:
void func(void) __attribute__((naked));
void func(void)
{
//function code
}
在Keil的汇编函数中还可以使用汇编伪指令,比如"PRESERVE8"对齐控制指令,这个显然在GCC中也是无法识别的,为了达到同样的效果,可以在上述的两个属性中加入aligned(8)来实现。如:
// Methon1:
__attribute__((always_inline,aligned(8))) void func(void){
// function code
}
// Methon2:
void func(void) __attribute__((naked, aligned(8)));
void func(void)
{
//function code
}