分类: 嵌入式
2012-07-08 22:28:22
一般来讲,在C中内联汇编语句要比纯粹的汇编语言代码复杂的多,需要解决如何分配寄存器、如何与C代码中的变量相结合的问题。
在Linux下的arm汇编语法格式不同于ADS下面的汇编语法格式,但是arm的指令都遵从于ARM的规范。在Linux下的C程序里面内联汇编代码,特别需要注意格式的问题。
从大的方面来讲,内联的汇编代码在C源文件中的区域标识不同。最基本的格式是:
__asm__(“asm statements”);
如果是多条汇编指令的话,需要用”\n\t”将它们隔开。如下所示:
__asm__(
“asm statements\n\t”
“asm statements\n\t”
…
“asm statements”);
完整的内联汇编代码格式如下:
__asm__(“asm statements” : outputs : inputs : registers-modified);
内联的汇编代码语句被”:”分割为4部分;其中,第一部分为汇编代码本身,通常成为指令部,格式与纯汇编代码是相同的。指令部是必须的,其他部分如果没有必要,可以省略。
在C中内联汇编,需要处理的一个问题就是如何与C语句中的变量相结合、传入汇编代码、从汇编代码中传出改变的值。在内联汇编代码的指令部中,使用占位符来表示需要使用寄存器的操作数,有几个占位符就表示有几个变量需要和寄存器相结合,汇编器在编译和连接的时候就会相应的根据后面的约束条件进行处理。
输出约束和输入约束的格式相同,是这样一种结构:
“constraint”(variable)
指令部后面紧接著就是输出部,它用来规定输出变量如何与占位符来结合。每一个条件可以成为一个约束,必要的时候可以使用多个约束,相互之间使用逗号隔开。一般情况下,每个输出约束都是以输出修饰符=开始,然后紧跟一个约束代码,最后是相结合的变量名称。如果变量既需要输入又需要输出,那么必须使用修饰符+。
紧接着就是输入部,它用来规定仅仅作为输入的变量如何与占位符相结合。它与输入部相似,由于只是输入,所以一般是不用输出修饰符(比如上面提到的=和+)的。
有时进行某些操作的时候,可能还会需要多个寄存器来保存中间的结果,这样就难免会破坏原有寄存器的内容。在gcc内联汇编的格式中的最后一部分可以对将产生副作用的寄存器进行说明,以便gcc能够采用相应的措施。
常见的输入输出修饰符和约束代码介绍
约束代码 意义
r 使用任何可用的通用寄存器
m 使用变量的内存位置
g 使用任何可用的寄存器和内存位置
i 使用立即数的值
输入输出修饰符 意义
= 只能写入操作数
+ 可读可写操作数
& 在内联函数完成之前,可以删除或者重新使用操作数
一个内联汇编的实例
#include
int main() {
int a = 10, b = 0, c = 0;
__asm__ __volatile__(
“mov r0, %2\n\t”
“add r0, r0, #5\n\t”
“mov %1, r0\n\t”
“mov %0, r0”
: “=r”(b), “=r”(c)
: “r”(a));
printf(“b = %d\nc= %d\n”, b, c);
return 0;
}