本文最后更新于:8 个月前
ARM体系结构与编程 3.5 基本ARM指令的应用
算术逻辑运算指令的应用
跳转指令的应用
Load/store指令的应用
批量load/store指令的应用
信号量指令的应用
与系统相关的一些指令的应用
3.5.1 算术逻辑运算指令的应用
位操作指令应用 将r2中的高8位数据传送到r3的低8位中
1 2 3 4 5 6 7 8 9 10 MOV R0 , R2 , LSR #24 ORR R3 , R0 , R3 , LSL #8 OR MOV R0 , R2 , ROR #24 MOV R3 , #0 / BIC R3 , R3 , #0xFF ORR R3 , R0 , R3
实现乘法的指令段
1 2 3 4 5 6 7 8 9 10 11 12 13 MOV R0 , R0 , LSL #1 ;2*R0 ADD R0 , R0 , R0 , LSL #1 ;3*R0 RSB R0 , R1 , R0 , LSL #2 ;4*R0-R1 MOV R0 , R0 , LSL #n ;2^n*R0 ADD R0 , R0 , R0 , LSL #n ;(2^n+1)*R0 RSB R0 , R0 , R0 , LSL #n ;(2^n-1)*R0
ARM指令的特色:两个操作在一条指令中完成。
64位数据运算
R0,R1存放64位数据的低32位和高32位;R2,R3存放64位数据的低32位和高32位:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ADDS R0 , R0 , R2 ADC R1 , R1 , R3 SUBS R0 , R0 , R2 SBC R1 , R1 , R3 CMP R1 , R3 CMPEQ R0 , R2
注意:进位标志C在CPSR中
内存中数据存储方式的转换
big endian<–> little endian
R0=ABCD <–> R0=DCBA
1 2 3 4 5 6 EOR R1 , R0 , R0 , ROR #16 ;R1=A^C, B^D, C^A, D^B BIC R1 , R1 , #0xFF0000 ;R1=A^C, 0, C^A, D^B MOV R0 , R0 , ROR #8 ;R0= D, A, B, C EOR R0 , R0 , R1 , LSR #8 ;LSR: 0, A^C, 0, C^A
1 2 3 4 5 6 MOV R2 , #0xFF ORR R2 , R2 , #0xFF0000 AND R1 , R2 , R0 AND R0 , R2 , R0 , ROR #24 ORR R0 , R0 , R1 , ROR #8
3.5.2 跳转指令的应用
子程序调用
BL指令在指令跳转操作的同时保存当前PC寄存器值,用于从被调用的子程序中返回。
1 2 3 4 5 6 7 8 9 BL function_name SUB R2 ,R1 ,R0 function_name MOV PC , LR
注意:B和BL指令的区别。
条件执行-最大公约数
最大公约数C语言代码:
1 2 3 4 5 6 7 8 9 int gcd (int a, int b) { while (a ! = b) if (a > b) a = a - b; else b = b - a; return a; }
最大公约数ARM汇编代码:
1 2 3 4 5 6 7 8 gcd cmp r0 , r1 beq stop blt less sub r0 , r0 , r1 b gcdless sub r1 , r1 , r0 b gcdstop
最大公约数ARM汇编代码(条件执行):
代码执行前r0中存放a,r1中存放b;代码执行后r0中存放a和b的最大公约数:
1 2 3 4 5 6 gcd CMP R0 , R1 SUBGT R0 , R0 , R1 SUBLT R1 , R1 , R0 BNE gcd MOV PC , LR
条件判断语句(C语言代码)
1 2 if (a == 0 || b == 1 ) c = d + e;
代码执行前r0中存放a,r1中存放b;代码执行后r2中存放d和e的和:
1 2 3 4 CMP R0 , #0 CMPNE R1 , #1 ADDEQ R2 , R3 , R4
注意:两个条件按顺序进行判断,如果第一个条件不成立,则后面的条件无需进行判断
循环语句
对于一个for或while循环:
1 2 3 4 5 6 MOV R0 , #loopcount loop SUBS R0 , R0 , #1 BNE loop
注意:此时SUB指令必需带后缀S。
多路分支程序语句
代码根据maxindex的不同值跳转不同的代码段,这里要求各目标代码段的大小都为
1 2 3 4 5 6 7 8 9 10 11 12 CMP R0 , #maxindex ADDLO PC , PC , R0 , LSL #RoutineSizeLog2 B IndexOutofRange ……Index0Handler ……Index1Handler …..Index2Handler ……IndexOutofRange ……
3.5.3 load/store指令的应用
链表操作
在链表中搜索与某一个数据相等的元素。链表中的每个元素包括两个字,第一个字中包含一个字节数据;第二个字中包含指向下一个链表元素的指令,当这个指针为0时表示链表结束。
1 2 3 4 5 6 7 llsearch CMP R0 , #0 LDRNEB R2 , [R0 ] CMPNE R1 , R2 LDRNE R0 , [R0 , #4 ] BNE llsearch MOV PC , LR
简单的串比较
比较两个串的大小:R0指向第一个串,R1指向第二个串。
1 2 3 4 5 6 7 8 9 10 11 strcmp LDRB R2 , [R0 ], #1 LDRB R3 , [R1 ], #1 CMP R2 , #0 CMPNE R3 , #0 BEQ return CMP R2 , R3 BEQ strcmpreturn SUB R0 , R2 , R3 MOV PC , LR
长跳转
通过直接向PC寄存器中存取数据,程序可以实现在4GB的地址空间的任意跳转,这种跳转叫做长跳转 。
1 2 3 4 5 ADD LR , PC , #4 LDR PC , [PC , #-4 ] DCD function return_here ADD
多路跳转 (比较前面的5. 多路分支程序语句)
通过函数地址表实现多路转移,其中maxendex为跳转的最大索引号,R0中为跳转的索引号。
1 2 3 4 5 6 7 CMP R0 , #maxindex LDRLO PC , [PC , R0 , LSL #2 ]B IndexOutofRangeDCD Handler0 DCD Handler1DCD Handler2
注意:这里子程序没有限定相同的大小。
3.5.4 批量load/store指令的应用
简单的块复制
一次将48个字数据从R12作为首地址的一段连续的内存单元复制到R13作为首地址的一段连续的内存单元。R14为源数据区末地址。
1 2 3 4 5 6 loop LDMIA R12 !, {R0 -R11 } STMIA R13 !, {R0 -R11 } CMP R12 , R14 BLO loop
思考:当数据块大小不是一次搬移数据的倍数时,程序如何设计?
LDM/STM应用实例-上机编程实践 1 2 3 4 5 6 7 SOURCE DCD 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 DCD 11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 ,19 ,20 DCD 21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 DCD 31 ,32 ,33 ,34 ,35 ,36 ,37 ,38 ,39 ,40 DCD 41 ,42 ,43 ,44 ,45 ,46 ,47 ,48 DEST DCD 0
子程序进入和退出时数据的保存和恢复
在调用子程序时,通常利用寄存器r0-r3传递参数和返回结果,这几个参数由子程序的调用者来保存,其他的子程序将要用到的寄存器在子程序入口处保存,在子程序返回前恢复这些寄存器。
1 2 3 4 5 6 function STMFD R13 !, {R4 -R12 , R14 } LDMFD R13 !, {R4 -R12 , PC }
3.5.5 信号量指令的应用 信号量用于实现对临界区数据访问的同步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 MVN R2 , #0 spinin SWP R3 , R2 , [R0 ] CMN R3 , #1 BEQ spinin CMP R3 , #0 STRNE R3 , [R0 ] BNE spinin STR R1 , [R0 ]
3.5.6 与系统相关的一些指令的应用
SWI中断处理程序
SWI指令使处理器切换到特权模式,在特权模式下请求特定的系统服务(由操作系统提供)。
SWI指令执行时通常完成下面的工作:
1 2 3 4 5 6 7 8 9 10 R14_svc = SWI指令的下面一条指令的地址SPSR_svc = CPSRCPSR [4 :0 ] = 0 b10011 ; supervisor modeCPSR [5 ] = 0 ; TCPSR [6 ] = 1 ; FCPSR [7 ] = 1 ; Iif high vectors configured then PC = 0 xFFFF0008else PC = 0 x00000008
当程序执行到SWI指令时,程序跳转到0x00000008处执行,由于该处是一条跳转指令,程序接着跳转到下面中断服务程序开始处执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 SWIHandler STMFD sp !, {R0 -R3 , R12 , LR } MRS R0 , SPSR TST R0 , #0x20 LDRNEH R0 , [LR , #-2 ] BICNE R0 , R0 , #0xFF00 LDREQ R0 , [LR , #-4 ] BICEQ R0 , R0 , #0xFF000000 CMP R0 , #MaxSWI LDRLS PC , [PC , R0 , LSL #2 ] B SWIOutofRange DCD SWIHANDLER0 DCD SWIHANDLER1 LDMFD sp !, {R0 -R3 , R12 , PC }^
3.5 本章小节 本章系统的介绍了ARM指令集中的基本指令,以及各指令的应用场合及方法,由基本指令还可以派生出一些新的指令,但使用方法与基本指令类似。与常见的如X86、MIPS体系结构的汇编指令相比较,ARM指令系统无论是从指令集本身,还是从寻址方式上,都相对复杂一些。
Thumb指令集作为ARM指令集的一个子集,其使用方法与ARM指令集类似,在此未作详细的描述,但这并不意味着Thumb指令集不如ARM指令集重要,事实上,他们各自有其自己的应用场合。