混合使用C、C++和汇编语之:内联汇编和嵌入型汇编的使用
12.1 内联汇编和嵌入型汇编的使用
内联汇编和嵌入型汇编是包含在C' target='_blank' style='cursor:pointer;color:#D05C38;text-decoration:underline;'>C/C++编译器中的汇编器。使用它可以在C/C++程序中实现C/C++语言不能完成的一些工作。例如,在下面几种情况中必须使用内联汇编或嵌入型汇编。
· 程序中使用饱和算术运算(Saturating arithmetic),如SSAT16 和 USAT16指令。
· 程序中需要对协处理器进行操作。
· 在C或C++程序中完成对程序状态寄存器的操作。
使用内联汇编编写的程序代码效率也比较高。
12.1.1 内联汇编
1.内联汇编语法
内联汇编使用"_asm"(C++)和"asm"(C和C++)关键字声明,语法格式如下所示。
· __asm("instruction[;instruction]"); // 必须为单条指令
__asm{instruction[;instruction]}
· __asm{
...
instruction
...
}
· asm("instruction[;instruction]"); // 必须为单条指令
asm{instruction[;instruction]}
· asm{
...
instruction
...
}
内联汇编支持大部分的ARM指令,但不支持带状态转移的跳转指令,如BX和BLX指令,详见ARM相关文档。
由于内联汇编嵌入在C或C++程序中,所有在用法上有其自身的一些特点。
① 如果同一行中包含多条指令,则用分号隔开。
② 如果一条指令不能在一行中完成,使用反斜杠"/"将其连接。
③ 内联汇编中的注释语句可以使用C或C++风格的。
④ 汇编语言中使用逗号","作为指令操作数的分隔符,所以如果在C语言中使用逗号必须用圆括号括起来。如,__asm {ADD x, y, (f(), z)}。
⑤ 内联汇编语言中的寄存器名被编译器视为C或C++语言中的变量,所以内联汇编中出现的寄存器名不一定和同名的物理寄存器相对应。这些寄存器名在使用前必须声明,否则编译器将提示警告信息。
⑥ 内联汇编中的寄存器(除程序状态寄存器CPSR和SPSR外)在读取前必须先赋值,否则编译器将产生错误信息。下面的例子显示了内联汇编和真正汇编的区别。
错误的内联汇编函数如下所示。
int f(int x)
{
__asm
{
STMFD sp!, {r0} // 保存r0不合法,因为在读之前没有对寄存器写操作
ADD r0, x, 1
EOR x, r0, x
LDMFD sp!, {r0} // 不需要恢复寄存器
}
return x;
}
将其进行改写,使它符合内联汇编的语法规则。
int f(int x)
{
int r0;
__asm
{
ADD r0, x, 1
EOR x, r0, x
}
return x;
}
下面通过几个例子进一步了解内联汇编的语法。
① 字符串拷贝
下面的例子使用一个循环完成了字符串的拷贝工作。
#include <stdio.h>
void my_strcpy(const char *src, char *dst)
{
int ch;
__asm
{
loop:
LDRB ch, [src], #1
STRB ch, [dst], #1
CMP ch, #0
BNE loop
}
}
int main(void)
{
const char *a = "Hello world!";
char b[20];
my_strcpy (a, b);
printf("Original string: '%s'\n", a);
printf("Copied string: '%s'\n", b);
return 0;
}
② 中断使能
下面的例子通过读取程序状态寄存器CPSR并设置它的中断使能位bit[7]来禁止/打开中断。需要注意的是,该例只能运行在系统模式下,因为用户模式是无权修改程序状态寄存器的。
__inline void enable_IRQ(void)
{
int tmp;
__asm
{
MRS tmp, CPSR
BIC tmp, tmp, #0x80
MSR CPSR_c, tmp
}
}
__inline void disable_IRQ(void)
{
int tmp;
__asm
{
MRS tmp, CPSR
ORR tmp, tmp, #0x80
MSR CPSR_c, tmp
}
}
int main(void)
{
disable_IRQ();
enable_IRQ();
}
③ 分隔符的计算
下面的例子计算两个整数数组中分隔符","的个数。该例子显示了如何在内联汇编中访问C或C++语言中的数据类型。该例中的内联汇编函数mlal()被编译器优化为一条SMLAL指令,可以使用-S –interleave编译选项使编译器输出汇编结果。
#include <stdio.h>
/* change word order if big-endian */
#define lo64(a) (((unsigned*) &a)[0]) /* long long型的低32位 */
#define hi64(a) (((int*) &a)[1]) /* long long型的高32位 */
__inline __int64 mlal(__int6
C C++ 汇编语言 ARM 内联汇编 嵌入型汇编 相关文章:
- RedHatLinux新手入门教程(5)(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- VXWORKS内核分析(11-11)
- 嵌入式开发工具简介(11-09)
- Linux2.4内核为我们带来了什么?(11-12)
- RedHatLinux新手入门教程(11-12)