ARM常用的汇编指令

一. 汇编指令格式

一个完整的ARM指令通常由操作码+操作数组成, 指令的编码格式如下:

   <opcode> {<cond> {s} <Rd>,<Rn> {,<operand2>}}
  • 使用<>标起来的是必选项, 使用{}标起来的是可选项
  • opcode是二进制机器指令操作码, 如MOV﹑ADD这些汇编指令都是操作码的指令助记符。
  • cond: 执行条件, ARM为减少分支跳转的指令个数,允许类似BEQ、BNE等形式的组合指令。
  • S: 是否影响CPSR(状态寄存器)中的标志位, 如SUBS指令会影响CPSR寄存器中的N﹑Z﹑C﹑V标志位,而SUB指令不会。
  • Rd: 目标寄存器。
  • Rn:第一个操作数的寄存器。
  • operand2: 第二个可选的操作数,灵活使用第二个操作数可以提高代码的效率。

二. 存储访问指令

ARM属于RSIC指令集,不能自己对内存里的数据进行直接操作, 只能通过Load/Store的指令来实现, 所以当我们要对内存中的数据进行操作时, 先要将内存中的数据加载到寄存器中, 然后在寄存器中对数据进行处理,最后将结果重新存储在内存中。

寄存器和内存中传输的指令

LDR  R1, [R0]    	;将R0的值作为地址, 将该地址中的数据保存到R1
STR  R1, [R0]		;将R0的值作为地址, 将R1的值存到这个地址空间中.
LDRB/STRB			;每次读取一个字节, LDR/STR默认每次读取4字节.
LDM/STM				;批量加载/储存指令, 在一组寄存器和一片内存之间进行数据传输.
SWP R1,R1,[R0]     	;将R1与R0中的地址指向的内存单元的数据进行交换
SWP R1,R2,[R0]		;[R0]存到R1, 将R2存到[R0]

堆栈格式
FA ->满递增堆栈
FD->满递减堆栈
EA->空递增堆栈
ED->空递减堆栈

LDMFD SP!, {R0-R2,R14}   	;将内存中的数据依次加载到R0,R1,R2,R14中
STMFD SP!, {R0-R2,R14}		;将R0,R1,R2,R14中数据依次压入栈中

PUSH {R0-R2,R14}			;将R0,R1,R2,R14依次压入栈中
POP	 {R0-R2,R14} 			;将栈中依次弹出数据到R0,R1,R2,R14中

三. 数据传输指令

寄存器和寄存器之间传输的指令, 需要使用MOV, MVN指令,格式如下:

MOV R1 ,#1	;将立即数1传到寄存器R1中
MOV R1 ,R0	;将R0寄存器中的值传送到R1寄存器中
MOV PC ,LR  ;子程序返回
MVN R0 ,#0XFF  ;将立即数0xFF取反后赋值给R0
MVN R0 ,R1	;将R1取反后赋值给R0

四. 算数运算指令

算数运算指令包括加减乘除和与或非等 指令格式如下:
ADD {cond} {S} Rd, Rn, operand2 ; 加法
ADC {cond} {S} Rd, Rn, operand2 ; 带进位加法
SUB {cond} {S} Rd, Rn, operand2 ; 减法
AND {cond} {S} Rd, Rn, operand2 ; 与
ORR {cond} {S} Rd, Rn, operand2 ; 或
EOR {cond} {S} Rd, Rn, operand2 ; 非
BIC {cond} {S} Rd, Rn, operand2 ; 位清除
cond: 执行条件, ARM为减少分支跳转的指令个数,允许类似BEQ、BNE等形式的组合指令。
S: 是否影响CPSR(状态寄存器)中的标志位, 如SUBS指令会影响CPSR寄存器中的N﹑Z﹑C﹑V标志位,而SUB指令不会。
operand2: 第二个可选的操作数,灵活使用第二个操作数可以提高代码的效率。

PS:

ADD R2,R1,#1		;R2=R1+1
ADC R2,R1,#3        ;R2=R1+3+C  //(C是CPSR寄存器中进位)
SUB R2,R1,R0        ;R2=R1-R0
SBC R2,R1,R3        ;R2=R1-R3-C //(C是CPSR寄存器中借位)
AND R2,R0,#3		;R2=R0&3
BIC R0,R0,#3		;R0=R0&(~3)

操作数operand2 解析
用法

1.#constant
2.Rm{, shift}

七.在C语言中内嵌汇编代码

为了能在c程序中内嵌汇编代码, ARM编译器在ANSI C标准的基础上扩展了一个关键字__asm. 通过这个关键字, 我们就可以在C程序中内嵌ARM汇编代码. 在C程序中内嵌汇编代码的格式如下.

__asm
{
	指令 /*我是注释*/
	...
	[指令]
}
//main.c
int src[10] = {1,2,3,4,5,6,7,8,9};
int dst[10] = {0};

int data_copy_c(void)
{
	for(int i = 0; i < 10; i++)
		dst[i] = src[i];
	return 0;
}

int data_copy_asm(void)
{
	__asm
	{
		LDR R0, =src
		LDR R1, =dst
		MOV R2, #10
	LOOP:
		LDR R3, [R0],#4
		STR R3, [R1],#4
		SUBS R2, R2, #1
		BNE LOOP	
	}
}

为了能在C程序中内嵌汇编代码,不同的编译器基于ANSI C标准扩展了不同的关键字,使用的汇编格式可能也可能不太一样,如GUN ARM编译器提供了一个__asm__ 关键字,它的使用方法如下.

__asm__ __volatile__
{
	"汇编语句;"
	...
	"汇编语句;"
}

八.汇编代码调入C语言

在汇编程序中调用C程序, 在调用的时候, 我们要注意根据ATPCS规则来完成参数的通道的传递,并配置好C程序传递参数和保存局部变量所依赖的堆栈环境,然后使用BL指令直接跳转即可.

IMPORT sum
AREA SUM_ASM,CODE,READONLY
	EXPORT SUM_ASM
SUM_ASM:
	LDR R0, = 0X03;
	LDR R1, = 0X04;
	BL sum
	MOV PC,LR
	END

int sum(int a,int b)
{
	int result;
	result = a + b;
	printf("result = %d\n",result);
	return result;
}

int main(void)
{
	SUM_ASM();
	return 0;
}

在函数调用过程中, 当要传递的参数大于4个数时,除了前4个参数使用寄存器R0-R4传递,剩余的参数要使用堆栈进行传递,这个时候需要编译器通过堆栈指针来进行管理和维护.

  • 28
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值