4.1内联汇编

为什么需要用内联汇编

目前编译器都比较智能,能将 C 代码转换为高效率的汇编指令,但是对于某些特殊指令(如 ldrex 、 strex 实现互斥访问)或特殊算法编译器则无法正常转换,此时则需要使用汇编来实现相应的功能,如果不想创建单独的汇编文件则需要采用在C语言中嵌入汇编指令的方式来实现。

内联汇编的基本格式

如下是一段内联汇编代码的基本格式

	__asm__ asm-qualifiers (
		AssemblerTemplate
		:OutputOperands
		:InputOperands
		:Clobbers
	);

asm :固定格式,表示这是一段内联汇编代码
asm-qualifiers :限定符,通常是 volatile ,表示不对此段内联汇编代码进行优化
AssemblerTemplate :汇编指令列表,每条指令都用用双引号包含起来,并以\n结尾,如 “mov %0, %1\n”
OutputOperands :输出操作数,当有多个操作数时,用逗号进行隔开,单个操作数的格式如下:
[asmSymbolicName] “constraint” (cvariablename)
[asmSymbolicName] :符号名,与 C 代码中的变量名类似,在汇编中可以使用 %[asmSymbolicName] 来引用这个操作数,此部分是可以省略的,若省略后再汇编中则通过 %n 来引用此操作数(n=0~+∞,为操作数出现的顺序)
constraint :参数约束,采用的取值如下:
m :表示要传入有效的地址
r :使用通用寄存器来保存这个操作数
i :表示可以传入一个立即数
以上这些取值还可以加上下列修饰符:
无 :被修饰的操作符是只读的
= :被修饰的操作符只写
+ :被修饰的操作符可读写
& :被修饰的操作符只能作为输出,它会为此操作数分配一个单独的寄存器
cvariablename:操作数对应的C语言的变量名
InputOperands :输入操作数,当有多个操作数时,用逗号隔开,格式如下
[asmSymbolicName] “constraint” (cvariablename)
Clobbers :指明修改了那些寄存器或内存,常用的取值如下:
cc :表示修改了标志寄存器
memory :表示修改了内存
r0 ~ r15 :表示修改了相应的寄存器

程序示例

如下是一个使用内联汇编实现的加法函数

#include 
#include 

void add1(int a1, int b1, int *sum1)
{
	__asm__ volatile (
		"add r4, %1, %2\n"		//将a1+b1赋值到r4中,r4 = a1+b1
		"ldr r3, %0\n"			//将sum的值加载到如中,r3 = sum1
		"str r4, [r3]\n"		//把r3作为地址,并r4的值写入r3所指的内存,*r3 = r4
		:"=&m"(sum1)			//输出参数
		:"r"(a1), "r"(b1)		//输入参数
		:"cc", "r3", "r4"		//改变了内存、r3、r4
	);
}

void add2(int a1, int b1, int *sum1)
{
	__asm__ volatile (
		"add r4, %1, %2\n"		//将a1+b1赋值到r4中,r4 = a1+b1
		"str r4, [%0]\n"		//把sum1作为地址并把r4的值写入,*sum1 = r4
		:"=&r"(sum1)			//输出参数
		:"r"(a1), "r"(b1)		//输入参数
		:"cc", "r4"				//改变了内存、r4
	);
}

//这个函数中使用了汇编符号名,汇编语句中通过%[符号名]的方式引用操作数
void add3(int a1, int b1, int *sum1, int a2, int b2, int *sum2)
{
	__asm__ volatile (
		"add %[s1], %[a1], %[b1] \n"						//*sum1 = a1+b1
		"add %[s2], %[a2], %[b2] \n"						//*sum2 = a2+b2
		:[s1]"=&r"(*sum1), [s2]"=&r"(*sum2)					//输出参数
		:[a1]"r"(a1), [b1]"r"(b1), [a2]"r"(a2), [b2]"r"(b2)	//输入参数
		:"cc"												//改变了内存
	);
}

int main(int argc, char *argv[])
{
	int sum1;
	int sum2;
	
	add1(1, 3, &sum1);
	printf("add1:%d + %d = %d\n", 1, 3, sum1);
	add2(1, 3, &sum1);
	printf("add2:%d + %d = %d\n", 1, 3, sum1);
	add3(1, 3, &sum1, 4, 5, &sum2);
	printf("add3:%d + %d = %d; %d + %d = %d\n", 1, 3, sum1, 4, 5, sum2);
	return 0;
}

你可能感兴趣的:(汇编,linux,arm开发)