ARM 汇编指令集

0. ARM寄存器


    R13: SP

    R14: LR

1. 跳转指令

    跳转指令用于实现程序流程的跳转,在ARM 程序中有两种方法可以实现程序流程的跳转:
    1) 使用专门的跳转指令。
    2) 直接向程序计数器PC 写入跳转地址值。

   通过向程序计数器PC 写入跳转地址值,可以实现在4GB 的地址空间中的任意跳转,在跳转之前结合使用

    MOV  LR,PC 

    等类似指令,可以保存将来的返回地址值,从而实现在4GB 连续的线性地址空间的子程序调用。ARM 指令集中的跳转指令可以完成从当前指令向前或向后的32MB 的地址空间的跳转,包括以下4 条指令:


1.1 跳转指令B

     B{条件} 目标地址

     B 指令是最简单的跳转指令。一旦遇到一个B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的

值由汇编器来计算(参考寻址方式中的相对寻址)。它是24 位有符号数,左移两位后有符号扩展为32 位,表示的有效偏移为26 位(前后32MB 的地址空间)。以下指令:
    # 程序无条件跳转到标号Label 处执行

    B  Label ;

   

    #当CPSR 寄存器中的Z 条件码置位时,程序跳转到标号Label 处执行
    CMP R1,#0 

    BEQ Label

1.2  带连接的跳转指令BL

       BL{条件} 目标地址

START   …
              BL   NEXT           @跳转到标号NEXT处,同时保存当前PC到R14中
              …                   
              …
NEXT…                            @子程序入口
              MOV   PC,R14        @返回 

           BL 是另一个跳转指令,但跳转之前,会在寄存器R14 中保存PC 的当前内容,因此,可以通过将R14 的内容重新加载到PC 中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。

1.3 BLX 指令

      BLX 目标地址

      BLX 指令从ARM 指令集跳转到指令中所指定的目标地址,并将处理器的工作状态从ARM 状态切换到Thumb 状态,该指令同时将PC 的当前内容保存到寄存器R14 中。因此,当子程序使用Thumb 指令集,而调用者使用ARM 指令集时,可以通过BLX 指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14
值复制到PC 中来完成。

1.4 BX 指令

      BX{条件} 目标地址

      BX 指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM 指令,也可以是Thumb 指令。

MOV   R0,  #0X0200
BX    R0 


2. 算术运算指令


2.1 不带进位加法指ADD

     ADD{条件}{S} 目的寄存器,操作数1<寄存器>,操作数2
     ADD 指令用于把两个操作数相加,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
     示例如下:

ADD R0,R1,R2        @ R0 = R1 + R2
ADD R0,R1,#256      @ R0 = R1 + 256
ADD R0,R2,R3,LSL#1 @ R0 = R2 + (R3 << 1)

2.2 带进位加法指令ADC

      ADC{条件}{S} 目的寄存器,操作数1<寄存器>,操作数2
     ADC 指令用于把两个操作数相加,再加上CPSR 中的C 条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就可以做比32 位大的数的加法,注意不要忘记设置S 后缀来更改进位标志。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。

    以下指令序列完成两个128 位数的加法,第一个数由高到低存放在寄存器R7~R4,第二个数由高到低存放在寄存器R11~R8,运算结果由高到低存放在寄存器R3~R0:

ADDS R0,R4,R8    @加低端的字
ADCS R1,R5,R9    @加第二个字,带进位
ADCS R2,R6,R10   @加第三个字,带进位
ADC  R3,R7,R11   @加第四个字,带进位

2.3 不带进位减法SUB 

      SUB{条件}{S} 目的寄存器,操作数1,操作数2
      SUB 指令用于把操作数1 减去操作数2,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。
      示例如下:

SUB R0,R1,R2         @R0 = R1 - R2
SUB R0,R1,#256       @R0 = R1 - 256
SUB R0,R2,R3,LSL#1  @R0 = R2 - (R3 << 1)

2.4 带进位减法指令SBC 

        SBC{条件}{S} 目的寄存器,操作数1,操作数2
        SBC 指令用于把操作数1 减去操作数2,再减去CPSR 中的C 条件标志位的反码,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进位标志来表示借位,这样就可以做大于32 位的减法,注意不要忘记设置S 后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。
示例如下:

SUBS  R0, R3, R6            @减最低位字节,不带进位
SBCS  R1, R4, R7            @减第二个字,带进位
SBCS  R2, R5, R8            @减第三个字,带进位

#三句话实现了96bit减法运算,由于ARM寄存器宽度只有32bit所以分三次相减

2.5 不带进位逆向减法指令RSB

        RSB{条件}{S} 目的寄存器,操作数1,操作数2
        RSB指令称为逆向减法指令,用于把操作数2 减去操作数1,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。
示例如下:

RSB   R0, R1, R2                     @R0 = R2- R1
RSB   R0, R1,  #112                  @R0 = 112- R1
RSB   R0, R1, R2,  LSL#1             @R0 = (R2<<1)-R1

2.6 带进位逆向减法指令RSC 

        RSC{条件}{S} 目的寄存器,操作数1,操作数2
        RSC 指令用于把操作数2 减去操作数1,再减去CPSR 中的C 条件标志位的反码,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进位标志来表示借位,这样就可以做大于32 位的减法,注意不要忘记设置S 后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。

        示例如下:

RSBS   R0, R6, R3                    @减最低字节的字,不带进位
RSCS   R1, R7, R4                    @减第二个字,带进位
RSCS   R2, R8, R5                    @减第三个字,带进位
#三句话实现了96bit减法运算,由于ARM寄存器宽度只有32bit所以分三次相减

2.7乘法指令

     乘法指令中的所有操作数、目的寄存器必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器,同时,目的寄存器和操作数1 必须是不同的寄存器

2.7.1  32位乘法指令MUL
          MUL{条件}{S} 目的寄存器,操作数1<寄存器>,操作数2<寄存器>
          MUL 指令完成将操作数1 与操作数2 的乘法运算,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的有符号数或无符号数。
         示例如下:

MUL R0,R1,R2     @R0 = R1 × R2
MULS R0,R1,R2    @R0 = R1 × R2,同时设置CPSR中的相关条件标志位

2.7.2 乘-累加指令 MLA
        MLA{条件}{S} 目的寄存器,操作数1,操作数2,操作数3
        MLA 指令完成将操作数1 与操作数2 的乘法运算,再将乘积加上操作数3,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的有符号数或无符号数。
        示例如下:

MLA R0,R1,R2,R3      @R0 = R1 × R2 + R3
MLAS R0,R1,R2,R3     @R0 = R1 × R2 + R3,同时设置CPSR 中的相关条件标志位

2.7.3 有符号长乘指令SMULL
        SMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
        SMULL 指令完成将操作数1 与操作数2 的乘法运算,并把结果的低32 位放置到目的寄存器Low 中,结果的高32 位放置到目的寄存器High 中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的有符号数
        示例如下:

SMULL R0,R1,R2,R3  @R0 = (R2 × R3)的低32 位;R1 = (R2 × R3)的高32 位
                      @SMULL指令实现64bit有符号数乘法

2.7.4 无符号数长乘指令 UMULL
         UMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
         UMULL 指令完成将操作数1 与操作数2 的乘法运算,并把结果的低32 位放置到目的寄存器Low 中,结果的高32 位放置到目的寄存器High 中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的无符号数
示例如下:

UMULL R0,R1,R2,R3  @R0 = (R2 × R3)的低32 位;R1 = (R2 × R3)的高32 位
                      @UMULL指令实现64bit无符号数乘法

2.7.5 有符号长乘-累加指令 SMLAL
        SMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
        SMLAL 指令完成将操作数1 与操作数2 的乘法运算,并把结果的低32位同目的寄存器Low 中的值相加后又放置到目的寄存器Low 中,结果的高32 位同目的寄存器High 中的值相加后又放置到目的寄存器High中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操
作数1 和操作数2 均为32 位的有符号数。
         对于目的寄存器Low,在指令执行前存放64 位加数的低32 位,指令执行后存放结果的低32位。对于目的寄存器High,在指令执行前存放64 位加数的高32 位,指令执行后存放结果的高32 位。
示例如下:

SMLAL R0,R1,R2,R3    @R0 = (R2 × R3)的低32 位+ R0;R1 = (R2 × R3)的高32 位+ R1
                        @SMLAL 指令为64位有符号乘-累加指令

2.7.6 无符号长乘-累加指令 UMLAL
         UMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
         UMLAL 指令完成将操作数1 与操作数2 的乘法运算,并把结果的低32 位同目的寄存器Low 中的值相加后又放置到目的寄存器Low 中,结果的高32 位同目的寄存器High 中的值相加后又放置到目的寄存器High 中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的无符号数。
        对于目的寄存器Low,在指令执行前存放64 位加数的低32 位,指令执行后存放结果的低32 位。对于目的寄存器High,在指令执行前存放64 位加数的高32 位,指令执行后存放结果的高32 位。
       示例如下:

UMLAL R0,R1,R2,R3   @R0 = (R2 × R3)的低32 位+ R0;R1 = (R2 × R3)的高32 位+ R1
                       @UMLAL 指令为64位无符号乘-累加指令

2.8 比较指令CMP

      CMP{条件} 操作数1,操作数2
      CMP 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR 中条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操作数1 与操作数2 的关系(大、小、相等),例如,当操作数1 大于操作操作数2,则此后的有GT 后缀的指令将可以执行。
      示例如下:

CMP R1,R0    @将寄存器R1 的值与寄存器R0 的值相减,并根据结果设置CPSR 的标志位
CMP R1,#100  @将寄存器R1 的值与立即数100相减,并根据结果设置CPSR 的标志位

2.9 负数比较指令CMN

     CMN{条件} 操作数1,操作数2
     CMN 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数取反后进行比较,同时更新CPSR 中条件标志位的值。该指令实际完成操作数1 和操作数2 相加,并根据结果更改条件标志位。
示例如下:

CMN R1,R0    @将寄存器R1 的值与寄存器R0 的值相加,并根据结果设置CPSR 的标志位
CMN R1,#100  @将寄存器R1 的值与立即数100相加,并根据结果设置CPSR 的标志位


3. 逻辑运算指令

3.1 “与”指令AND

         AND{条件}{S} 目的寄存器,操作数1,操作数2
         AND 指令用于在两个操作数上进行逻辑与运算,并把结果放置到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于屏蔽操作数1 的某些位。
示例如下:

AND R0,R0,#3        @该指令保持R0的0、1 位,其余位清零。

3.2 “或”指令ORR

        ORR{条件}{S} 目的寄存器,操作数1,操作数2
        ORR 指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数1 的某些位。
        示例如下:

ORR R0,R0,#3       @该指令设置R0 的0、1 位,其余位保持不变。


3.3 “异或”指令EOR

        EOR{条件}{S} 目的寄存器,操作数1,操作数2
        EOR 指令用于在两个操作数上进行逻辑异或运算,并把结果放置到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于反转操作数1 的某些位。
        示例如下:

EOR R0,R0,#3     @该指令反转R0 的0、1 位,其余位保持不变。

3.4 位清除指令BIC

       BIC{条件}{S} 目的寄存器,操作数1,操作数2
       BIC 指令用于清除操作数1 的某些位,并把结果放置到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。操作数2 为32 位的掩码,如果在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不变。
示例如下:

BIC R0,R0,#%1011  @该指令清除R0 中的位0、1、和3,其余的位保持不变。

3.5 测试比较指令TST

      TST{条件} 操作数1,操作数2
      TST 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位与运算,并根据运算结果更新CPSR 中条件标志位的值。操作数1 是要测试的数据,而操作数2 是一个位掩码,该指令一般用来检测是否设置了特定的位。
示例如下:

TST R1,#%1     @用于测试在寄存器R1 中是否设置了最低位(%表示二进制数)
TST R1,#0xffe  @将寄存器R1 的值与立即数0xffe 按位与,并根据结果设置CPSR的标志位,应用中会在TST之后加一条跳转指令

3.6 异或测试指令TEQ 

      TEQ{条件} 操作数1,操作数2
      TEQ 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位异或运算,并根据运算结果更新CPSR 中条件标志位的值。该指令通常用于比较操作数1 和操作数2 是否相等。
示例如下:

TEQ R1,R2 @将寄存器R1 的值与寄存器R2的值按位异或,并根据结果设置CPSR 的标志位


4. 数据传送指令

 4.1 数据传送指令MOV

      MOV{条件}{S} 目的寄存器,源操作数
     MOV 指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR 中条件标志位的值,当没有S时指令不更新CPSR 中条件标志位的值。
     示例如下:
    

MOV R1,R0         @将寄存器R0 的值传送到寄存器R1
MOV PC,R14        @将寄存器R14 的值传送到PC,常用于子程序返回
MOV R1,R0,LSL#3  @将寄存器R0 的值左移3位后传送到R1

4.2 反向传送指令MVN

      MVN{条件}{S} 目的寄存器,源操作数
      MVN 指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV 指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。其中S 决定指令的操作是否影响CPSR 中条件标志位的值,当没有S 时指令不更新CPSR 中条件标志位的值。
      示例如下:
MVN R0,#0  @将立即数0 取反传送到寄存器R0 中,完成后R0=-1


4.3 程序状态字内容送通用寄存器指令 MRS  

      MRS{条件} 通用寄存器,程序状态寄存器(CPSR 或SPSR)
     MRS 指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令一般用在以下两种情况:
       1) 当需要改变程序状态寄存器的内容时,可用MRS 将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
       2) 当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
示例如下:

MRS R0,CPSR   @传送CPSR 的内容到R0
MRS R0,SPSR   @传送SPSR 的内容到R0
               @MRS指令是唯一可以直接读取CPSR和SPSR寄存器的指令

4.4 写状态寄存器指令 MSR 

       MSR{条件} 程序状态寄存器(CPSR 或SPSR)_<域>,操作数
       MSR 指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。<域>用于设置程序状态寄存器中需要操作的位,32 位的程序状态寄存器可分为4 个域:
        1) 位[31:24]为条件标志位域,用f 表示;
        2) 位[23:16]为状态位域,用s 表示;
        3) 位[15:8]为扩展位域,用x 表示; 
        4) 位[7:0]为控制位域,用c 表示;
     该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR 指令中指明将要操作的域。
示例如下:

MSR CPSR,R0   @传送R0 的内容到CPSR
MSR SPSR,R0   @传送R0 的内容到SPSR
MSR CPSR_c,R0 @传送R0 的内容到CPSR,但仅仅修改CPSR中的控制位域


5. 存储器访问指令(加载/存储指令)

    ARM 微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。

5.1 字加载指令LDR

      LDR{条件} 目的寄存器,<存储器地址>
      LDR 指令用于从存储器中将一个32 位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32 位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC 作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。该指令在程序设计中比较常用,且寻址方式灵活多样,请读者认真掌握。
      示例如下:

LDR R0,[R1]              @将存储器地址为R1 的字数据读入寄存器R0。
LDR R0,[R1,R2]          @将存储器地址为R1+R2 的字数据读入寄存器R0。
LDR R0,[R1,#8]          @将存储器地址为R1+8 的字数据读入寄存器R0。
LDR R0,[R1,R2]!         @将存储器地址为R1+R2 的字数据读入寄存器R0,并将新地址R1+R2 写入R1。
LDR R0,[R1,#8]!         @将存储器地址为R1+8 的字数据读入寄存器R0,并将新地址R1+8 写入R1。
LDR R0,[R1],R2          @将存储器地址为R1 的字数据读入寄存器R0,并将新地址R1+R2 写入R1。
LDR R0,[R1,R2,LSL#2]!  @将存储器地址为R1+R2×4 的字数据读入寄存器R0,并将新地址R1+R2×4 写入R1。
LDR R0,[R1],R2,LSL#2   @将存储器地址为R1 的字数据读入寄存器R0,并将新地址R1+R2×4 写入R1。

#注意:使用LDR指令时字节地址是4的倍数

5.2 字存储指令 STR

      STR{条件} 源寄存器,<存储器地址>
      STR 指令用于从源寄存器中将一个32 位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR。
      示例如下:

STR R0,[R1],#8   @将R0中的字数据写入以R1 为地址的存储器中,并将新地址R1+8 写入R1。
STR R0,[R1,#8]   @将R0中的字数据写入以R1+8为地址的存储器中。

5.3 字节加载指令 LDRB (低8位)

      LDR{条件}B 目的寄存器,<存储器地址>
      LDRB 指令用于从存储器中将一个8 位的字节数据传送到目的寄存器中,同时将寄存器的高24 位清零。该指令通常用于从存储器中读取8位的字节数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
      示例如下:

LDRB R0,[R1]      @将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB R0,[R1,#8]  @将存储器地址为R1+8 的字节数据读入寄存器R0,并将R0 的高24位清零。

5.4 字节存储指令 STRB

      STR{条件}B 源寄存器,<存储器地址>
      STRB 指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。
      示例如下:

STRB R0,[R1]      @将寄存器R0 中的字节数据写入以R1 为地址的存储器中。
STRB R0,[R1,#8]  @将寄存器R0 中的字节数据写入以R1+8 为地址的存储器中。

5.5 半字加载指令 LDRH (低16位)

      LDR{条件}H 目的寄存器,<存储器地址>
      LDRH 指令用于从存储器中将一个16 位的半字数据传送到目的寄存器中,同时将寄存器的高16 位清零。该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
      示例如下:

LDRH R0,[R1]      @将存储器地址为R1的半字数据读入寄存器R0,并将R0 的高16 位清零。
LDRH R0,[R1,#8]  @将存储器地址为R1+8 的半字数据读入寄存器R0,并将R0 的高16 位清零。
LDRH R0,[R1,R2]  @将存储器地址为R1+R2 的半字数据读入寄存器R0,并将R0 的高16 位清零。

5.6 半字存储指令 STRH

      STR{条件}H 源寄存器,<存储器地址>
      STRH 指令用于从源寄存器中将一个16 位的半字数据传送到存储器中。该半字数据为源寄存器中的低16 位。
      示例如下:

STRH R0,[R1]       @将寄存器R0中的半字数据写入以R1 为地址的存储器中。
STRH R0,[R1,#8]   @将寄存器R0 中的半字数据写入以R1+8 为地址的存储器中。

5.7 有符号字节加在指令 LDRSB (带符号低8位)

       指令格式与LDRB类似。

LDRSB   R0, [R1, R2]       @将地址R1+R2上的8位数值送R0, R0的高24位用符号位扩展

5.8 有符号半字加载指令 LDRSH  (带符号低16位)

      指令格式与LDRH类似。

LDRSH   R0, [R1]           @将地址R1上的低16位数据送R0, R0的高16位用符号位扩展

5.9 批量数据加载/存储指令LDM/STM

      批量数据加载/存储指令ARM 微处理器所支持批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令则完成相反的操作。

     在STM、LDM指令中,寄存器列表与内存单元的对应关系:编号低的寄存器对应于内存中低地址单元;编号高的寄存器对应于内存中高地址单元。

     常用的加载存储指令如下:

     LDM(或STM){条件}{类型}  基址寄存器{!},寄存器列表{^}
     LDM(或STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。其中,{类型}为以下几种情况(它表示:LDM/STM指令地址模式选择  ):

  IA    先传送数据,后基址加4;
  IB    先基址加4,后传送数据;
  DA  先传送数据,后基址减4;
  DB  先基址减4,后传送数据;
  FD  满递减堆栈(Full Descending, ATPCS使用此规则,sp指向最后一个压入的值,数据栈由高地址低地址生长);
  ED  空递减堆栈;
  FA   满递增堆栈;
  EA  空递增堆栈;

  (I: Increase, D: Descend, A: After, B: Before, F: Full, E: Empty)

     {!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。

     基址寄存器不允许为R15,寄存器列表可以为R0~R15 的任意组合。{^}为可选后缀,当指令为LDM 且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR 复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
    示例如下:

STMFD R13!,{R0,R4-R12,LR} @将寄存器列表中的寄存器(R0,R4-R12,LR)存入堆栈。
LDMFD R13!,{R0,R4-R12,PC} @将堆栈内容恢复到寄存器(R0,R4-R12,PC)。

   STMFD指令的寻址方式为事前递减方式(DB),
   STMFD SP!, {R0-R7,LR}    @把数据压栈
  其伪代码如下:

   SP = SP - 9 x 4;
   address = SP; 

   for i = 0 to 7
      Memory[address] = Ri;
      address  = address + 4;

   Memory[address] = LR;

   LDMFD指令的寻址方式为事后递增方式(IA)
   LDMFD SP!, {R0-R7,PC}^  @恢复现场,异常处理返回
   其伪代码如下:

  address = SP;
  for i = 0 to 7
     Ri = Memory[address]
     address = address + 4;
  
  PC = Memory[address]
  SP = address;

5.10 寄存器 存储器字交换指令 SWP

       SWP{条件} 目的寄存器,源寄存器1,[源寄存器2]

       SWP 指令用于将源寄存器2 所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1 中的字数据传送到源寄存器2 所指向的存储器中。显然,当源寄存器1 和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
       示例如下:

SWP R0,R1,[R2]  @将R2 所指向的存储器中的字数据传送到R0 , 同时将R1 中的字数据传送到R2 所指向的存储单元。
SWP R0,R0,[R1]  @该指令完成将R1 所指向的存储器中的字数据与R0 中的数据交换。

5.11 寄存器与存储器字节交换指令SWPB (高24位填0,低8位有数据)

       SWP{条件}B 目的寄存器,源寄存器1,[源寄存器2]
       SWPB 指令用于将源寄存器2 所指向的存储器中的字节数据传送到目的寄存器中,目的寄存器的高24 清零,同时将源寄存器1 中的字节数据传送到源寄存器2 所指向的存储器中。显然,当源寄存器1 和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
     示例如下:

SWPB R0,R1,[R2]  @将R2 所指向的存储器中的字节数据传送到R0,R0 的高24位清零,同时将R1 中的低8 位数据传送到R2 所指向的存储单元。
SWPB R0,R0,[R1]  @该指令完成将R1 所指向的存储器中的字节数据与R0 中的低8 位数据交换。

6 移位指令 

6.1 逻辑左移操作 LSL (低位填0)

      通用寄存器,LSL 操作数
    LSL可完成对通用寄存器中的内容进行逻辑的左移操作,按操作数所指定的数量向左移位,低位用零来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)
示例如下:

MOV R0, R1, LSL #2 ;将R1 中的内容左移两位后传送到R0 中。

MOV   R1, #0X01
MOV   R0, R1, LSL #2
MOV   R2, #2
MOV   R0, R1, LSL R2


6.2 算数左移操作 ASL (低位填0)

     通用寄存器,ASL 操作数
     ASL可完成对通用寄存器中的内容进行算术的左移操作,按操作数所指定的数量向左移位,低位用零来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)
示例如下:

MOV   R1, #0X01
MOV   R0, R1, ASL #2


6.3 逻辑右移操作 LSR (高位填0) 

    通用寄存器,LSR 操作数
    LSR 可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用零来填充。其中,操作数可以是通用寄存器,也
可以是立即数(0~31)。
    示例如下:


MOV R0, R1, LSR #2 @将R1 中的内容右移两位后传送到R0 中,左端用零来填充


6.4 算术右移操作 ASR (高位用第31位的值填充)

     通用寄存器,ASR 操作数
     ASR 可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用第31 位的值来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
   示例如下:

MOV R0, R1, ASR #2  @将R1 中的内容右移两位后传送到R0 中,左端用第31 位的值来填充。

6.5 循环右移操作 R0R (高位由低位填充)

      通用寄存器,ROR 操作数
      ROR可完成对通用寄存器中的内容进行循环右移的操作,按操作数所指定的数量向右循环移位,左端用右端移出的位来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。显然,当进行32 位的循环右移操作时,通用寄存器中的值不改变。
    示例如下:


MOV R0, R1, ROR#2  @将R1 中的内容循环右移两位后传送到R0 中。

6.6 带扩展的循环右移操作 RRX (低位-> C -> 高位)

      通用寄存器,RRX 操作数
      RRX可完成对通用寄存器中的内容进行带扩展的循环右移的操作,按操作数所指定的数量向右循环移位,左端用进位标志位C来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
      示例如下:

MOV R0, R1, RRX #2 @将R1 中的内容进行带扩展的循环右移两位后传送到R0 中。

7 异常产生指令

7.1 软中断指令 SWI 

     SWI{条件}  24 位的立即数
     SWI指令用于产生软件中断以便用户程序能调用操作系统的系统例程。操作系统在SWI 的异常处理程序中提供相应的系统服务,指令中24 位的立即数指定用户程序调用系统例程的类型,相关参数通过通用寄存器传递,当指令中24 位的立即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0 的内容决定,同时,参数通过其他通用寄存器传递。
    示例如下:

SWI 0x02    @该指令调用操作系统编号为02 的系统例程。


7.2 断点中断指令 BKPT 

    BKPT 16 位的立即数
    BKPT 指令产生软件断点中断,可用于程序的调试。


8 协处理指令

8.1 协处理器数据操作指令 CDP 

    CDP{条件} 协处理器编号,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2
    CDP 指令用于ARM 处理器通知ARM 协处理器执行特定的操作,若协处理器不能成功完成特定的操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,目的寄存器和源寄存器均为协处理器的寄存器,指令不涉及ARM 处理器的寄存器和存储器。
    示例如下:

CDP P3,2,C12,C10,C3,4    @该指令完成协处理器P3的初始化


CDP P1, 1, C2, C3, C4         @指令要操作的协处理器为p1 ,1为协处理器p1的指令操作代码。
                              @c2、c3、c4 为协处理器p1的寄存器。CPD指令的使用并不影响
                              @ARM微处理器中CPSR寄存器的状态位。

8.2 协处理器数据读取指令LDC 

      LDC{条件}{L} 协处理器编号,目的寄存器,[源寄存器]
      LDC 指令用于将源寄存器所指向的存储器中的字数据传送到目的寄存器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指令为长读取操作,如用于双精度数据的传输。
      示例如下:

LDC P3,C4,[R0]        @将ARM 处理器的寄存器R0 所指向的存储器中的字数据传送到协处理器P3 的寄存器C4 中。
LDC p5, c2, [R0, #4]    @将内存地址为R0+4处的数据送到协处理器p5的寄存器c2中。
LDC p5, c1, [R0,R1]     @将内存地址为R0+R1处的数据送到协处理器p5的寄存器c1中。

8.3 协处理器数据写入指令STC 

      STC{条件}{L} 协处理器编号,源寄存器,[目的寄存器]
      STC 指令用于将源寄存器中的字数据传送到目的寄存器所指向的存储器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指令为长读取操作,如用于双精度数据的传输。
      示例如下:

STC P3,C4,[R0]        @将协处理器P3 的寄存器C4中的字数据传送到ARM 处理器的寄存器R0所指向的存储器中。


8.4 ARM微处理器到协处理器的数据传送指令MCR 

      MCR{条件} 协处理器编号,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2
      MCR 指令用于将ARM 处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,源寄存器为ARM 处理器的寄存器,目的寄存器1 和目的寄存器2 均为协处理器的寄存器。
    示例如下:

MCR P3,3,R0,C4,C5,6   @该指令将ARM 处理器寄存器R0 中的数据传送到协处理器P3 的寄存器C4 和C5 中。

8.5 协处理器到ARM寄存器的数据传送指令MRC 

    MRC{条件} 协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2
    MRC 指令用于将协处理器寄存器中的数据传送到ARM 处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,目的寄存器为ARM 处理器的寄存器,源寄存器1 和源寄存器2 均为协处理器的寄存器。
    示例如下:

MRC P3,3,R0,C4,C5,6 @该指令将协处理器P3的寄存器中的数据传送到ARM 处理器寄存器中。



<think>我们正在讨论ARM架构下的汇编指令集。根据引用[2],ARM处理器以其小尺寸、低功耗和性能著称,是32位RISC架构。引用[1]提到ARMv7-A架构中包含了硬件整数除法指令(sdiv和udiv)。引用[3]提到一本关于x86汇编的书籍,但这里我们关注ARM汇编。 ARM架构的汇编语言是一种低级语言,用于直接控制ARM处理器。以下是一些基本概念和常用指令的介绍: ### 1. **寄存器** ARM架构有16个32位通用寄存器,命名为R0到R15。其中: - R0-R12:通用目的寄存器。 - R13 (SP):堆栈指针(Stack Pointer)。 - R14 (LR):链接寄存器(Link Register),用于存储子程序返回地址。 - R15 (PC):程序计数器(Program Counter)。 此外,还有当前程序状态寄存器(CPSR),用于存储条件标志(如零标志、进位标志等)和当前处理器状态(如模式)。 ### 2. **基本指令格式** ARM指令通常遵循以下格式: ``` <opcode>{<cond>}{S} <Rd>, <Rn>, <Operand2> ``` 其中: - `opcode`:操作码,如MOV、ADD等。 - `cond`:条件执行后缀(可选),如EQ(相等)、NE(不相等)。 - `S`:设置条件标志(可选)。 - `Rd`:目标寄存器。 - `Rn`:第一个操作数寄存器。 - `Operand2`:第二个操作数,可以是寄存器、立即数或移位后的寄存器。 ### 3. **常用指令** #### 数据传送指令 - `MOV`:将数据从一个寄存器或立即数移动到另一个寄存器。 ```assembly MOV R0, #10 @ 将立即数10加载到R0 MOV R1, R0 @ 将R0的值复制到R1 ``` - `LDR`:从内存加载数据到寄存器。 ```assembly LDR R0, [R1] @ 将R1指向的内存地址的内容加载到R0 ``` - `STR`:将寄存器内容存储到内存。 ```assembly STR R0, [R1] @ 将R0的值存储到R1指向的内存地址 ``` #### 算术指令 - `ADD`:加法。 ```assembly ADD R0, R1, R2 @ R0 = R1 + R2 ADD R0, R1, #5 @ R0 = R1 + 5 ``` - `SUB`:减法。 ```assembly SUB R0, R1, R2 @ R0 = R1 - R2 ``` - `MUL`:乘法(32位结果)。 ```assembly MUL R0, R1, R2 @ R0 = R1 * R2 ``` - `SDIV`和`UDIV`:有符号除法和无符号除法(需要硬件支持,如ARMv7-A及以上)。 ```assembly SDIV R0, R1, R2 @ R0 = R1 / R2(有符号) ``` #### 逻辑指令 - `AND`:按位与。 ```assembly AND R0, R1, R2 @ R0 = R1 & R2 ``` - `ORR`:按位或。 ```assembly ORR R0, R1, R2 @ R0 = R1 | R2 ``` - `EOR`:按位异或。 ```assembly EOR R0, R1, R2 @ R0 = R1 ^ R2 ``` - `BIC`:位清除(将Rn中与Operand2中为1的位对应的位清零)。 ```assembly BIC R0, R1, #0xFF @ 清除R1的低8位,结果存R0 ``` #### 分支指令 - `B`:无条件分支(跳转)。 ```assembly B label @ 跳转到标签label处 ``` - `BL`:带链接的分支(用于函数调用),将返回地址存入LR。 ```assembly BL function @ 调用函数function ``` - `BX`:分支并切换指令集(用于Thumb/ARM状态切换)。 ```assembly BX LR @ 返回到LR指定的地址,并可能切换状态 ``` #### 比较指令 - `CMP`:比较两个操作数,设置条件标志。 ```assembly CMP R0, R1 @ 比较R0和R1,设置标志位 ``` - `TST`:测试位(按位与,设置标志但不保存结果)。 ```assembly TST R0, #1 @ 测试R0的最低位 ``` ### 4. **条件执行** ARM指令可以通过添加条件后缀来实现条件执行。例如: ```assembly ADDEQ R0, R1, R2 @ 如果前一条指令导致EQ(相等)条件成立,则执行加法 ``` ### 5. **示例程序** 以下是一个简单的ARM汇编程序,计算1到10的和: ```assembly MOV R0, #0 @ 初始化总和为0 MOV R1, #1 @ 计数器从1开始 loop: ADD R0, R0, R1 @ 累加 ADD R1, R1, #1 @ 计数器加1 CMP R1, #10 @ 比较计数器和10 BLE loop @ 如果小于等于10,则继续循环 @ 此时R0中存储了总和(55) ``` ### 6. **汇编环境** 要编写和运行ARM汇编程序,可以使用交叉编译工具链(如GCC的ARM版本)和模拟器(如QEMU)。例如,使用`arm-linux-gnueabihf-as`和`arm-linux-gnueabihf-gcc`进行汇编和链接。 以上内容是对ARM汇编指令集的简要介绍。ARM汇编语言非常丰富,还包括许多其他指令和特性,如协处理器指令、SIMD指令(NEON)等,可根据需要进一步学习。 §§相关问题§§ 1. ARM架构中条件执行的具体规则是什么? 2. 如何在ARM汇编中实现函数调用和返回? 3. ARMv7和ARMv8架构在指令集上有哪些主要区别? 4. 如何用ARM汇编进行内存访问优化? 5. ARM汇编中的移位操作有哪些?</think>### ARM架构汇编指令集简介与使用 ARM架构是一种精简指令集(RISC)架构,以其低功耗、高性能和小尺寸著称[^2]。其汇编语言用于底层硬件控制和优化。以下是核心概念和用法: --- ### 一、ARM汇编基础 #### 1. **寄存器** - **16个32位通用寄存器**:R0-R12(数据操作),R13(SP:堆栈指针),R14(LR:链接寄存器),R15(PC:程序计数器)[^2]。 - **特殊寄存器**:CPSR(当前程序状态寄存器),存储条件标志(如零标志Z、进位标志C)。 #### 2. **指令格式** ARM指令通常为 **`操作码 目标寄存器, 操作数1, 操作数2`** 格式: ```assembly ADD R0, R1, R2 @ R0 = R1 + R2 SUB R3, R4, #10 @ R3 = R4 - 立即数10 ``` #### 3. **寻址模式** - **立即数寻址**:`MOV R0, #0xFF` - **寄存器寻址**:`ADD R1, R2, R3` - **寄存器间接寻址**:`LDR R0, [R1]`(从R1指向的内存加载数据) - **基址偏移寻址**:`STR R2, [R3, #4]`(地址为R3+4) --- ### 二、核心指令分类 #### 1. **数据传送** - `MOV R0, R1` @ 寄存器间复制 - `LDR R0, [R1]` @ 从内存加载到寄存器 - `STR R0, [R1]` @ 将寄存器值存储到内存 - `PUSH {R0, R1}` @ 压栈,`POP {R0, R1}` @ 弹栈 #### 2. **算术运算** - `ADD/SUB R0, R1, R2` @ 加/减 - `MUL R0, R1, R2` @ 乘法 - `SDIV/UDIV R0, R1, R2` @ 有符号/无符号除法(需硬件支持)[^1] #### 3. **逻辑运算** - `AND/ORR/EOR R0, R1, R2` @ 与/或/异或 - `LSL R0, R1, #2` @ 逻辑左移2位 - `ASR R0, R1, #3` @ 算术右移3位 #### 4. **控制流** - `B label` @ 无条件跳转 - `BL label` @ 跳转并保存返回地址到LR(用于函数调用) - `BX LR` @ 函数返回 - `CMP R0, R1` @ 比较R0和R1(设置CPSR标志) - `BEQ label` @ 若相等则跳转(基于CPSR) #### 5. **条件执行** 几乎所有指令可加条件后缀(如`ADDEQ`),提升效率: ```assembly CMP R0, #0 @ 检查R0是否为0 MOVEQ R1, #1 @ 若为0,则R1=1 MOVNE R1, #0 @ 若不为0,则R1=0 ``` --- ### 三、使用示例 #### 1. **函数调用与返回** ```assembly main: BL my_function @ 调用函数,返回地址存入LR ... my_function: PUSH {R4, LR} @ 保存寄存器 ... @ 函数逻辑 POP {R4, LR} @ 恢复寄存器 BX LR @ 返回 ``` #### 2. **内存访问优化** ```assembly LDR R0, [R1], #4 @ 加载R1指向的值后,R1自增4(自动后变址) STR R2, [R3, #8]! @ 存储前将R3+8(前变址) ``` #### 3. **循环求和(1到10)** ```assembly MOV R0, #0 @ 总和初始化为0 MOV R1, #1 @ 计数器i=1 loop: ADD R0, R0, R1 @ 累加 ADD R1, R1, #1 @ i++ CMP R1, #10 @ 检查i<=10 BLE loop @ 满足则继续循环 ``` --- ### 四、开发工具与注意事项 1. **工具链**: - 汇编器:`arm-linux-gnueabi-as` - 调试器:GDB + QEMU模拟器 - 编译器:GCC(`-S`选项生成汇编代码) 2. **关键特性**: - **Thumb模式**:16位指令集,代码密度更高。 - **条件执行**:减少分支指令,提升性能[^3]。 - **小端序**:数据存储与x86一致[^2]。 3. **内存操作**: - 需对齐访问(如LDR/STR地址需4字节对齐)。 - 使用`LDM/STM`批量加载/存储提高效率: ```assembly LDMIA R1!, {R2-R5} @ 从R1连续加载4个寄存器,R1自增 ``` --- ### 五、ARMv8扩展(64位) - 寄存器扩展至64位(X0-X30)。 - 新增指令如`LDP`(加载双寄存器): ```assembly LDP X0, X1, [X2] @ 从X2加载两个64位值到X0和X1 ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值