ARM汇编的一些常识

  • Post author:
  • Post category:其他



常用ARM指令


1. 数据传传输指令





mov   例:mov r1 r2  @两个寄存器数据之间的传递



mvn   与mov的区别是:mov是原封不动的将数据传输,而mvn是将数据按位取反后再传递

2. 算术指令

add sub rsb adc sbc rsc


3. 逻辑指令

and orr eor bic

4. 比较指令



cmp cmn tst tep



比较指令的特殊性:比较指令不用添加S后缀就可以影响CPSR的标志位。

5. 乘法指令



mvl mla nmull umlal smull smlal

6. 前导零计数



clz

7. CPSR访问指令   (CPSR比较特殊,需要专门指令来访问)



mrs / msr       mrs用来读cpsr,msr用来写



CPSR和SPSR两个寄存器的区别与联系:    CPSR是程序状态寄存器,整个SOC上只有1个,而SPSR有5个,分别在5种异常模式下,作用是当从普通模式进入异常模式
时,用来保存之前普通模式下的CPSR,以在返回普通模式下恢复CPSR。




8. 跳转指令



b bl bx



b:直接跳转(不用保存返回地址)



bl: 跳转前把返回地址放入到lr中,以便返回,用于函数调用



bx:跳转同时切换到ARM模式,一般用于异常处理跳转




9. 访问内存指令



ldr/str  ldm/stm  swp



ldr/str: 字节、半字、字的访问
ldr:该指令将内存的内容加载到通用寄存器。

str:该指令将寄存器的内容存入到内存空间。



ldm/stm:多字批量访问



swp  r1, r2, [r0]  寄存器和内存交换内容



swp  r1, r1, [r0]  @将r0存的内容送给前面r1寄存器,再将后面r1寄存器的内容传给内存r0



ARM汇编的立即数:合法立即数和非法立即数



ARM指令本身是32位的,除了指令标志和操作标志外,本身只能带很少位数的立即数。



合法立即数:经任意位数的移位后非零部分可以用8位表示。






10. 软中断指令



swi 主要用来实现操作系统的系统调用。



!的作用:

例:ldmia  r0!, {r2 – r3}

感叹号的作用就是将r0的值在ldm过程中的增加或者减少最后写到r0中去,也就是ldm过程中会改变r0的值。






^的作用:

例:


ldmfd  sp!,{r0-r6,pc}^



^的作用:在目标寄存器中有pc时,会同时将SPSR写入CPSR,一般用于从异常处理模式返回。

GNU汇编的一些符号

1. @  用来做注释

2. #  用来注释

3. : 以冒号结尾的是标号,表地址

4. .  表示当前指令的地址       @汇编循坏 b .

5. #  立即数面前要加#和$



GNU常用的伪指令

1. .global_start     @给_start外部链接属性

2. .section  .text   @指定当前断为代码段

3. .ascii  .byte  .short .long .word  .quad(双字)  .float  .string    @定义数据



汇编数据定义举例:



IRQ_START:



.word   0xcaffffff



等价于C语言



unsigned int IRQ_SRART = 0xcaffffff;

4. .align 4   @以16字节对其    2^4 = 16

5. .balignl  16  0xabcfdcac   @以16字节对其填充,填充内容为 0xabcfdcac



b: 表示位填充;  align 表示要对齐;  l 表示long,以4字节为单位填充;  16 表示16字节对齐

6. .equ    @相当于C的宏定义

7. .end    @标识文件结束

8. .include  @头文件包含

9. .arm / .code32    @声明以下为ARM指令

10. .thumb / .code16   @声明以下为thumb指令

GNU重要的几个伪指令

1. ldr   大范围的地址加载指令

2. adr   小范围的地址加载指令

3. adrl  中等范围的地址加载指令

4. nop   空操作



ARM中一般有一个ldr指令和一个ldr伪指令,为了避免数据的合法性,常用ldr伪指令。




adr总是以PC为基准来表示地址,指令本身和地址有关,可以用来检测程序当前运行地址在哪个地方。

ldr加载的地址和连接时给定的地址有关,由连接脚本决定。

8种寻址方式

1. 寄存器寻址  例:mov r1,r2    ;将r2的内容赋给r1

2. 立即寻址    例:mov r0,#0x0f  ;’#’表示后面是一个数,本指令的意思是将0x0f赋给r1

3. 寄存器移位寻址 例:mov r0, r1,lsl#3  ;将r1左移3位后赋给r1

4. 寄存器间接寻址 例:ldr r1, [r2]  ;把r2的内存地址赋给r1

5. 基址变址寻址   例:ldr r1,[r2, #4]  ;把r2地址加4再赋给r1

6. 多寄存器寻址   例:ldmia r1! , {r2-r7,r12} ;以r1地址为基地址,和以后的地址依次存到r2-r7和r12中  r1可以看作是一个数组的首地址

7. 堆栈寻址       例:sdmst fp! , {r1-r7,lr}



;用意跟ldmia一样,只是此时是将堆栈里的地址依次放入r1-r7,lr

8. 相对寻址       例:bep flag flag: ;标号表示入口地址(如函数)



版权声明:本文为aa1050416698原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。