微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 混合使用C、C++和汇编语之:内联汇编和嵌入型汇编的使用

混合使用C、C++和汇编语之:内联汇编和嵌入型汇编的使用

时间:08-30 来源:3721RD 点击:

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

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top