混合使用C、C++和汇编语之:内联汇编和嵌入型汇编的使用
编代码,但以下标识符除外:
· __cpp(expr);
· __offsetof_base(D, B);
· __mcall_is_virtual(D, f);
· __mcall_is_in_vbase(D, f);
· __mcall_this_offset(D, f);
· __vcall_offsetof_vfunc(D, f);
② 编译程序不为__asm 函数生成返回指令。如果要从 __asm 函数返回,必须将用汇编代码编写的返回指令包含到函数体内。由于嵌入式汇编执行__asm函数的顺序是在编译时定义好的,所有从一个内嵌汇编跳转到一个内嵌汇编程序是运行的,但在内联汇编中却不能实现。
③ __asm 函数调用遵循AAPCS规则。所以,即使在__asm 函数体内可用的汇编代码(例如,更改状态),在__asm函数和普通C或C++函数相互调用时,未必可用,因为此调用也必须遵循 AAPCS规则。
3.嵌入式汇编程序表达式和C或C++表达式之间的差异
嵌入式汇编表达式和C或C++表达式之间存在以下差异。
① 汇编程序表达式总是无符号的。相同的表达式在汇编程序和 C 或 C++ 中有不同值。例如:
MOV r0, #(-33554432 / 2) // 结果为 0x7f000000
MOV r0, #__cpp(-33554432 / 2) // 结果为 0xff000000
② 以0开头的汇编程序编码仍是十进制的。例如:
MOV r0, #0700 // 十进制 700
MOV r0, #__cpp(0700) // 八进制 0700 等于 十进制 448
③ 汇编程序运算符优先顺序与 C 和 C++ 不同。例如:
MOV r0, #(0x23 :AND: 0xf + 1) // ((0x23 & 0xf) + 1) => 4
MOV r0, #__cpp(0x23 & 0xf + 1) // (0x23 & (0xf + 1)) => 0
④ 汇编程序字符串不是以空字符为终止标志的:
DCB "no trailing null" // 16 bytes
DCB __cpp("I have a trailing null!!") // 25 bytes
| 注意 | 在_cpp标识符作用范围之内使用C或C++语法规则。 |
4.嵌入式汇编函数的生成
由关键字__asm声明的嵌入式汇编程序,在编译时将作为整个文件体传递给ARM汇编器。传递过程中,__asm函数的顺序保持不变(用模板实例生成的函数除外)。正是由于嵌入式汇编的这个特性,使得由一个__asm标识的嵌入式汇编程序调用在同一文件中的另一个嵌入式汇编程序是可以实现的。
当使用编译器 armcc 时,局部链接器(Partial Link)将汇编程序产生的目标文件与编译C程序的目标文件相结合,产生单个目标文件。
编译程序为每个 __asm 函数生成AREA命令。例如,以下__asm函数:
#include <cstddef>
struct X { int x,y; void addto_y(int); };
__asm void X::addto_y(int) {
LDR r2,[r0, #__cpp(offsetof(X, y))]
ADD r1,r2,r1
STR r1,[r0, #__cpp(offsetof(X, y))]
BX lr
}
对于此函数,编译程序生成:
AREA ||.emb_text||, CODE, READONLY
EXPORT |_ZN1X7addto_yEi|
#line num "file"
|_ZN1X7addto_yEi| PROC
LDR r2,[r0, #4]
ADD r1,r2,r1
STR r1,[r0, #4]
BX lr
ENDP
END
由上面的例子可以看出,对于变量offsetof的使用必须加__cpp()标识符才能引用,因为该变量是在cstddef头文件中定义的。
由__asm声明的常规函数被放在名为.emb_text的段(Section)中。这一点也是嵌入式汇编和内联汇编最大的不同。相反,隐式实例模板函数(Implicitly Instantiated Template Function)和内联汇编函数放在与函数名同名的区域(Area)内,并为该区域增加公共属性。这就确保了这类函数的特殊语义得以保持。
由于内联和模板函数的区域的特殊命名,所以这些函数不按照文件中定义的顺序排列,而是任意排序。因此,不能以__asm函数在原文件中的排列顺序,来判断它们的执行顺序,也就是说,即使两个连续排列的__asm函数,也不一定能顺序执行。
5.关键字__cpp
可用__cpp关键字从汇编代码中访问C或C++的编译时常量表达式,其中包括含有外部链接的数据或函数地址。标识符__cpp内的表达式必须是适合用作C++静态初始化的常量表达式(请参阅ISO/IEC 14882:1998中的3.6.2非本地对象初始化一节和本书的常量表达式一节)。
编译时,编译器将使用__cpp(expr) 的地方用汇编程序可以使用的常量所取代。例如:
LDR r0, =__cpp(&some_variable)
LDR r1, =__cpp(some_function)
BL __cpp(some_function)
MOV r0, #__cpp(some_constant_expr)
__cpp表达式中的名称可在__asm函数的C++上下文中查阅。__cpp表达式结果中的任何名称按照要求被损毁并自动为其生成IMPORT语句。
6.手动重复解决方案
可以在嵌入式汇
C C++ 汇编语言 ARM 内联汇编 嵌入型汇编 相关文章:
- RedHatLinux新手入门教程(5)(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- VXWORKS内核分析(11-11)
- 嵌入式开发工具简介(11-09)
- Linux2.4内核为我们带来了什么?(11-12)
- RedHatLinux新手入门教程(11-12)