ARM汇编指令

条件执行
EQ:相等则执行
NE:不相等则执行
GE:大于等于执行
LE:小于等于执行
GT:大于执行
LT:小于执行
AL:无条件执行

伪指令: 是有一些指令,不方便用汇编去实现,汇编器就提供一些指令,用于去实现一些
不好实现的一些功能,最终这些伪指令都要生成相应的汇编指令


操作数2 : 可以是一下几种情况:
1. 可以是寄存器
2. 可以使寄存器移位
3. 可以是立即数

立即数是存在于指令当中,
指令中是有12位,范围0~4095 ,这个数小,实际意义不大,因此发明立即数
什么是立即数: 一个字节的数循环右移(ROR)0 到30 之间的偶数位


装载32 bit常数到寄存器时
ldr rd ,= const (伪指令)
1. const 是立即数时,会变成mov指令
2. const 是有效数时,会变成mvn指令  //这个数本身是立即数或它取反后的数是立即数
3. const 不是有效数时,会变成ldr访问内存,先把这个数放到存储器中,然后再读回来
建议把常数装载到寄存器中时一律使用该伪指令


ARM处理器的八种寻址方式
1. 立即数寻址
也叫立即寻址,操作数本身就在指令中给出,去出指令也就取到了操作数。
立即数要求以#或$开头
  mov r1,#15                      //十进制
  mov r2,$3
  mov r3,#0x10                    //十六进制
  mov r4,#011                     //八进制
  mov r5,#0b01010000              //二进制     @0x50

2. 寄存器寻址
寄存器寻址就是利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常采用的一种的方式。
ADD R0,R1,R2      @R0=R1+R2
MOV R0,R1          @R0=R1

3. 寄存器移位寻址
ADD R0,R1,R2,LSL #2
mov r0,r1,lsl #2

4. 寄存器间接寻址
ldrb r1,[r0]           @ r1 = *r0 r1 = 0x11
mov r2,#5
str r2,[r0]              @ *r0 = r2 0x11->0x5
LDR STR Word
LDRB STRB Byte
LDRH STRH Halfword
LDRSB 带符号的byte load
LDRSH 带符号的halfword load

5. 基址变址寻址
基址变址寻址就是将基址寄存器的内容与指令中给出的偏移量相加,
得到一个有效的操作数的地址。通常用于访问连续的地址空间

前索引:   LDR R1 , [R0 , #4]      @ R0 表示的基地址, #4 偏移量,+-4K -4095 ~ 4095
                                   @ r1 = *( r0 + 4 )
           STR R1 , [R0 , #4]

自动索引: LDR R1 , [R0 , #4]!     @ R0 表示的基地址, #4 偏移量,+-4K -4095 ~ 4095
                                   @ r1 = *( r0 + 4 ),r0 +=4;
           STR R1 , [R0 , #4]!

后索引:   LDR R1 , [R0], #4       @ R0 表示的基地址, #4 偏移量,+-4K -4095 ~ 4095
                                   @ r1 = *r0 ,r0 +=4;
           STR R1 , [R0], #4

6. 相对寻址
b和bl
b和bl指令的解析:
   00020000 <step-0x10>:
   20000: e3a01001 mov r1, #1
   20004: ea000001 b 20010 <step>
   20008: e3a02002 mov r2, #2
   2000c: e3a03003 mov r3, #3
00020010 <step>:
   20010: e3a04004 mov r4, #4
   20014: eafffffe b 20014 <step+0x4>
     b lable <==> add pc ,pc #偏移量
     偏移量: 0x1
     偏移量左移两位: 0x1<<2 (偏移量是按照指令进行计算)
     pc = 0x200c
     pc + 偏移量 = 0x200c + 4
                 = 0x20010
跳转范围: 0到23 的范围: 0 ~ 16M ,去除符号位 +-8M 个指令
                                            +-32Mbytes

如何执行长跳转:
   ldr pc ,=lable (伪指令) 0~ 4G 范围装载

7.  多寄存器寻址

LDMIA R0!,{R1-R5} @ *r0 = R1,R2,R3,R4,R5 ,r0 +=4 ; i++
STMIA R0!,{R1-R5}

LDMIB R0!,{R1-R5} @ r0 +=4 ,*r0 = R1,R2,R3,R4,R5 ; ++i
STMIB R0!,{R1-R5}

LDMDA R0!,{R1-R5} @ *r0 = R1,R2,R3,R4,R5 ,r0 -=4 ; i--
STMDA R0!,{R1-R5}

LDMDB R0!,{R1-R5} @ r0 -=4 , *r0 = R1,R2,R3,R4,R5 ; --i
STMDB R0!,{R1-R5}

I : 增 D : 减
A : 后 B : 先

规则1: 内存的地址和寄存器的标号是对齐的
       内存的高地址对应寄存器的大编号
       内存的地地址对应寄存器的小编号
规则2: 用什么方式存,用相反的方式取  例如STMDA与LDMIB


8. 堆栈寻址

LDMFD R0!,{R1-R5} @ r0 -=4 , *r0 = R1,R2,R3,R4,R5 ; --i
STMFD R0!,{R1-R5}

LDMFA R0!,{R1-R5} @ r0 +=4 , *r0 = R1,R2,R3,R4,R5 ; ++i
STMFA R0!,{R1-R5}

LDMED R0!,{R1-R5} @ *r0 = R1,R2,R3,R4,R5, r0 -=4 ; i--
STMED R0!,{R1-R5}

LDMEA R0!,{R1-R5} @ *r0 = R1,R2,R3,R4,R5, r0 +=4 ; i++
STMEA R0!,{R1-R5}

F : 满 E : 空
A : 增 D : 减

规则1:
        内存的地址和寄存器的标号是对其的
        内存的高地址对应寄存器的大编号
        内存的地地址对应寄存器的小编号

规则2: 用什么方式存(压栈),用相同的方式读(出栈)
规则3: atpcs 标准是用FD方式入栈 FD 方式出栈  例如:STMFD与LDMFD
规则4: stmfd sp!,{r1-r5} <==> push {r1-r5}
       ldmfd sp!,{r1-r5} <==> pop {r1-r5}

乘法指令:
32位乘法:
mov r1,#100
mov r2,#200
mul r3,R1,R2
乘加指令
mov r1,#100
mov r2,#200
mov r3,#100
mla r4,r1,r2,r3   @r4=r1*r2+r3      
64位的乘法指令:
ldr r1,=0xffffffff
ldr r2,=0xffff
umull r4,r3,r1,r2 @ r4 存放低32位 r3存放高32位
smull r4,r3,r1,r2 @ r4 存放低32位 r3存放高32位

单寄存器数据传送
ldr r0,=myarry @ 伪指令 取标号所在地址 r0 = myarry
ldr r1,myarry  @ 但寄存器数据传送指令,取标号所在地址内的值    r1 = *myarry

LDR STR Word
LDRB STRB Byte
LDRH STRH Halfword
LDRSB 带符号的byte load
LDRSH 带符号的halfword load

交换指令: SWP
在寄存器和存储器之间,由一次存储器读和一次存储器写组成的原子操作
完成一个字节或字的交换。
ldr r0,=myarry  @ 伪指令 取标号所在地址 r0 = myarry
mov r1,#5
swp r2,r1,[r0]  @ r0 基地址,r1 要写入内存的值 ,r2要从内存中读出值 r2=*r0 ,*r0= r1
swpb r2,r1,[r0] @ r0 基地址,r1 要写入内存的值 ,r2要从内存中读出值 r2=*r0 ,*r0= r1


软件中断指令:
swi 0x1000000-1 @ pc -> lr_svc = 0x20018 A: 0x20014   (0x1000000-1 软中断号)
                @ pc = 0x08

psr指令:
mrs r0,cpsr   @ mov r0,cpsr
mrs r0,spsr   @用户模式下不能操作spsr
mov r0,#0xd3  
msr cpsr,r0   @ mov cpsr , r0
msr cpsr_c,r0 

伪指令:  
 adr r0,myarry @ 伪指令 r0 = 20018 <myarry>: 基于pc的偏移量 +-1K 
 adrl r1,myarry @ 伪指令 r1 = 20018 <myarry>: 基于pc的偏移量 +-256K 
 ldr r2,myarry @ 但寄存器数据传送 取标号所在地址内的值 r2 = * myarry 
 ldr r3,=myarry @ 伪指令 ,取编号所在的地址 r3 = myarry 0~4G 

gnu的伪指令集:
.arch armv7-a                cpu的体系结构
.fpu softvfp                 软件浮点库
.file "1.c"                  文件名
.global a                    声明一个符号为全局符号
.data                        用来定义一个数据段
.type a, %object             这个a是一个数据类型的
.type main, %function        函数类型
.size a, 1                   占用内存的大小,以字节计算
a:
 .byte 10                    申请一个字节的存储空间,把存储空间赋值为10
.align 1                     字节对其 2权次方 2个字节对其
align 2                      4个字节对齐
.section .rodata             用来定义一个段
 movw r3, #:lower16:a        传送a变量值的低16位
 movt r3, #:upper16:a        传送a变量值的高16位

uxtb r2, r3 把r3寄存器内的(一个字节的数)值扩展成一个32值,即对高24位清零 ,放到r2当中

     .equ aaaa , 0x0       汇编的宏定义

     .if aaaa              预编译
     mov r1,#1
     mov r2,#2
     .else
     mov r1,#2
     mov r2,#3
     .endif

.macro func                宏函数
 mov r3,#3
 mov r4,#4
.endm


局部标号:局部标号 主要在局部范围内使用而且局部标号可以重复出现。
它由两部组成开头是一个0-99直接的数字局部标号 后面加“:” 
1:
    mov r1,#1 
1:
    mov r2,#2
    b 1b
    mov r3,#3
1:
    mov r4,#4
1:
    mov r5,#5
F: 向地址增加的增加或则行号增加的方向
B:地址减少的方向或则是行号减少的方向


异常处理的异常向量: 基地址 + 偏移量
基地址: arm7 arm9 arm10基地址可以是0地址也可以是0xffff0000
                    arm11 cortex-a 这个基地址可以是任意地址
                    ldr r0,=0x20000 @ 设置异常向量表的基地址
                    mcr p15,0,r0,c12,c0,0 @ c12, Vector Base Address Register,
          偏移量: 固定不变的
ldr r0,=0x20000           @ 设置异常向量表的基地址
mcr p15,0,r0,c12,c0,0     @ c12, Vector Base Address Register,
mov r1,#1
mov r2,#2
mov r3,#3
mov r4,#4
mov r5,#5
swi 0x0                   
@ pc --> lr_svc = 0x20028 - 4 = 0x20024
@ pc = 基地址 + 偏移量
@    = 0x20000 +0x08(SWI偏移量)
@    = 0x20008


异常向量表存放的指令(4种):
1. b handler          @+-32M bytes 快
2. mov pc, #立即数    @#立即数 必须是立即数 快
3. ldr pc,=handler    @0到4G 慢
4. ldr pc ,lable      @0到4G 慢
   lable:
         .word handler

gnu内联汇编
int a = 10,b = 5,sum =0;
__asm__(
     "mov r0,%1\n\t"
     "add %0,%1,%2\n\t"
     :"+r"(sum)
     :"r"(a),"r"(b)
     :"r0"
);
/*
* 1. 内联汇编 使用关键字 asm 或者是 __asm__
* 2. 组成 括号使用引号的部分是指令部分,
* 3. 冒号部分: 第一个是输出参数列表
*              第二个是输入参数列表
*              第三个是修饰列表
* 4. %0 表示的是输出和输入参数列表的第1个参数(从上到下,从左到右) sum
*    %1表示的是 输出和输入参数列表的第2个参数(从上到下,从左到右) a
*    %2表示的是 输出和输入参数列表的第3个参数(从上到下,从左到右) b
* 5. "r" : 表示参数的是用一个寄存器去存放
*    "m" : 表示的是一个以有效的内存
*    "I" : 表示的一个立即数
* 6. + 表示的是这个参数可读可写
*    = 表示的是这个参数只可写
*   无 表示的是这个参数只读
*    & 被修饰的操作符只能作为输出
*/
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值