混合使用C、C++和汇编语之:内联汇编和嵌入型汇编的使用
例子中以">>>"的开头的行是程序的源码部分,紧接其后的是由编译器编译出的汇编代码。从上例可以很清楚地看出,源程序中使用了r5、r6和r7,但由编译器编译后的代码使用了寄存器r1、r2和r3。
另外,需要特别指出的是在内联汇编中使用寄存器必须先声明其变量类型,如上例中的"int r5,r6,r7"。如果不在使用前进行声明,编译器将给出以下错误信息。
#1267-D: Implicit physical register R3 should be defined as a variable
编译程序定义的虚拟寄存器有函数局部作用范围,即在同一个C函数中,涉及相同虚拟寄存器名称的多个asm语句或声明,访问相同的虚拟寄存器。
内联汇编没有为pc(r15)、lr(r14)和sp(r13)寄存器创建虚拟寄存器,而且不能在内联汇编代码中读取或直接修改它们的值。如果内联汇编程序中出现了对这些寄存器的访问,编译器将给出以下错误消息。例如,如果指定r14:
#20: identifier "r14" is undefined
内联汇编可以直接使用CPSR和SPSR对程序状态字进行操作,因为内联汇编中不存在虚拟处理器状态寄存器(PSR)。任何对 PSR 的引用总是指向物理 PSR。
4.内联汇编中的指令展开
内联汇编代码中的ARM指令可能会在编译过程中扩展为几条指令。扩展取决于指令、指令中指定的操作数个数以及每个操作数的类型和值。通常,被扩展的指令有以下两种情况:
· 含有常数操作的指令;
· LDM、STM、LDRD 和 STRD指令;
· 乘法指令MUL被扩展为一系列的加法和移位指令。
下面的例子说明了编译器如何对含有常数操作的指令进行扩展。
包含有常数操作的加法指令:
ADD r0,r0,#1023
被编译器编译为如下两条指令:
ADD r0,r0,#1024
SUB r0,r0,#1
| 注意 | 扩展指令对程序状态寄存器CPSR的影响:算术指令影响相应的NZCV标准位;其他指令设置NZ标志位不影响V标志位。 |
所有的LDM和STM指令被扩展为等效的LDR和STR指令序列。然而,在优化过程中,编译程序可能因此将单独的指令重组为一条LDM或STM指令。
5.内联汇编中的常数
指令中的标志符"#"是可选的(前面的例子中,指令中常数前均加了标志符"#")。如果在指令中使用了"#",则其后的表达式必为常数。
6.内联汇编指令对标志位的影响
内联汇编指令可能显式或隐式地更新处理器程序状态寄存器的条件标志位。在仅包含虚拟寄存器操作数或简单表达式操作数的内联汇编中,其执行结果是可以预见。如果指令中指定了隐式或显式更新条件标志位,则条件标志位根据指令的执行进行设置。如果未指定更新,则条件标志不会更改。如果内嵌汇编指令的操作数都不是简单操作数时或指令不显式更新条件标志位,则条件标志位可能会被破坏。一般情况下,编译程序不易诊断出对条件标志的潜在破坏。然而,在构造析构C++临时函数的操作数时,如果指令试图更新条件标志,编译程序将给予警告,因为析构函数可能会破坏条件标志位。
7.内联汇编指令中的操作数
内联汇编指令中的操作数分为以下4种。
· 虚拟寄存器
· 表达式操作数
· 寄存器列表
· 中间操作数
(1)虚拟寄存器
在内联汇编指令中指定的寄存器表示虚拟寄存器而不是实际的物理寄存器。由编译器编译的汇编代码中使用的物理寄存器可能与在指令中指定的不同。每个虚拟寄存器的初值是不可预测的,必须在读取之前将初值写入虚拟寄存器。如果在写入之前试图读虚拟寄存器,编译程序会给予警告。
(2)表达式操作数
在内联汇编指令中,可将函数自变量、C或C++变量和其他C或C++表达式指定为寄存器操作数。用作操作数的表达式必须为整数类型,如char、short、int或long,(长整型long long除外)或指针类型。当表达式作为内联汇编指令的操作数时,编译器在编译时自动增加一段代码计算表示式的值并将其加载到指定的寄存器中。
| 注意 | 数据类型中除char和short(默认为无符号类型)外,其他均为有符号类型。 |
下面的例子显示了编译器如何处理内联汇编中的表达式操作数。
程序源代码如下所示。
/* Example Operands */
void my_operand(void)
{
int i,j,total;
__asm
{
mov i,#0
mov j,#1
add total,j,i+j
}
}
int main(void)
{
C C++ 汇编语言 ARM 内联汇编 嵌入型汇编 相关文章:
- RedHatLinux新手入门教程(5)(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- VXWORKS内核分析(11-11)
- 嵌入式开发工具简介(11-09)
- Linux2.4内核为我们带来了什么?(11-12)
- RedHatLinux新手入门教程(11-12)