精华内容
下载资源
问答
  • ARM 指令集 寄存器和处理器模式(26-bit 体系) &(32-bit 体系) 程序状态寄存器和操纵它的指令 寄存器装载和存储指令 算术和逻辑指令 移位操作 乘法指令 比较指令 分支指令 条件执行 ...X86常用汇编指令 X86汇编伪指令
  • arm汇编指令

    2018-09-07 00:02:26
    arm汇编指令大全,帮助文件的格式,适合读代码时索引汇编指令,含RVDS和gcc的伪指令
  • ARM汇编指令集(带书签,完美精排)
  • ARM 底层指令集,用于嵌入式开发,用于提升性能的开发手册和文档,通常C语言开发使用内联函数指令
  • ARM汇编指令中文离线文档 目录: ARM 指令集 寄存器和处理器模式(26-bit 体系) 寄存器和处理器模式(32-bit 体系) 程序状态寄存器和操纵它的指令 寄存器装载和存储指令 算术和逻辑指令 移位操作 乘法...
  • ARM汇编指令查询手册

    2014-01-17 12:16:27
    本人正在学习ARM,无意间从网上找到这个资料。感觉比较实用。故而与君分享
  • ARM7汇编指令集.ppt

    2018-10-23 08:05:53
    ARM7汇编指令集.ppt 介绍ARM7汇编指令集和寻址方式的介绍,图文并茂。
  • ARM汇编指令集.pdf

    2019-12-13 18:45:45
    2.5 不带进位逆向减法指令 RSB RSB R0, R1, R2 ;R0←(R2)- (R1) RSB R0, R1, #112 ;R0← 112- (R1) RSB R0, R1, R2, LSL#1 ;...三句话实现了 96bit 减法运算,由于 ARM 寄存器宽度只有 32bit 所以分三次相减
  • ARM汇编指令(中文版).chm
  • ARM-汇编指令集-PDF版

    2020-10-31 16:35:01
    一份不错的ARM汇编笔记 ARM 将其技术授权给世界上许多著名的半导体、 软件和 OEM 厂商, 每个厂商得到的都是独一无二的ARM相关技术及服务,利用这种合作关系, ARM很快成为许多全球性RISC标准的缔造者
  • 0.1 指令与伪指令  汇编指令-CPU机器指令的助记符,经过编译后会得到一串1和0组成的机器码,可以由CPU读取执行。  汇编伪指令-编译器环境提供的,用来指导编译过程的“指令... 0.3 ARM汇编指令的特点  0.3.1 LDR
  • ARM 汇编指令

    千次阅读 2019-09-05 19:28:56
    跳转指令 B/BL label:跳转到label指令地址处执行,会首先把该指令的下一条指令地址保存到lr寄存器。 label偏移地址的计算: A: B/BL指令的地址;B:即将要跳转到的函数地址 label = (B - A) >>2;最终结果...

    ARM64

    寄存器

    • x0 - x30 共31个通用寄存器,均为64bit,w0 - w30用来访问低32bit;
    • x29:用来充当FP,intel是ebp;
    • x30:充当lr寄存器,用来保存函数返回后的下一条执行地址;
    • SP:保存栈顶指针,使用 SP/WSP来进行对SP寄存器的访问,64bit,intel是esp;
    • PC:程序计数器,俗称PC指针,总是指向即将要执行的下一条指令,在arm64中,软件是不能改写PC寄存器的,64bit
    • CPSR:状态寄存器,64bit;

    常规指令

    ARM64指令长度是32bit。

    • MOV X1,X0 ;将寄存器X0的值传送到寄存器X1
    • ADD X0,X1,X2 ;寄存器X1和X2的值相加后传送到X0
    • SUB X0,X1,X2 ;寄存器X1和X2的值相减后传送到X0
    • AND X0,X0,#0xF ; X0的值与0xF相位与后的值传送到X0
    • ORR X0,X0,#9 ; X0的值与9相位或后的值传送到X0
    • EOR X0,X0,#0xF ; X0的值与0xF相异或后的值传送到X0
    • LDR X5,[X6,#0x08] ;X6寄存器加0x08的和的地址值内的数据传送到X5
      LDR X0, [X1] Load from the address in X1
      LDR X0, [X1, #8] Load from address X1 + 8
      LDR X0, [X1, X2] Load from address X1 + X2
      LDR X0, [X1, X2, LSL, #3] Load from address X1 + (X2 << 3)
      LDR X0, [X1, W2, SXTW] Load from address X1 + sign extend(W2)
      LDR X0, [X1, W2, SXTW, #3] Load from address X1 + (sign extend(W2) << 3)
    • STR X0, [SP, #0x8] ;X0寄存器的数据传送到SP+0x8地址值指向的存储空间
    • STP x29, x30, [sp, #0x10] ;入栈指令,一个寄存器是8Bytes,因此需要0x10个地址偏移的数据
    • LDP x29, x30, [sp, #0x10] ;出栈指令,
    • CBZ ;比较(Compare),如果结果为零(Zero)就转移(只能跳到后面的指令)
    • CBNZ ;比较,如果结果非零(Non Zero)就转移(只能跳到后面的指令)
    • CMP ;比较指令,相当于SUBS,影响程序状态寄存器CPSR
    • B/BL ;绝对跳转#imm, 返回地址保存到LR(X30);B指令不改变LR寄存器,但BL指令修改LR寄存器
    • RET ;子程序返回指令,返回地址默认保存在LR(X30)

    跳转指令

    1. B/BL label:跳转到label指令地址处执行,会首先把该指令的下一条指令地址保存到lr寄存器。
      label偏移地址的计算:
      A: B/BL指令的地址;
      B:即将要跳转到的函数地址
      label = (B - A) >>2;最终结果右移2位,是因为指令地址是4字节对齐。
      示例: 400608 - 400664 = FFFFFFa4 >> 2 = FFFFFFe9
    0000000000400608 <test_add>:
      400608:       d10043ff        sub     sp, sp, #0x10
      40060c:       b9000fe0        str     w0, [sp,#12]
      400610:       b9000be1        str     w1, [sp,#8]
      400614:       b9400fe1        ldr     w1, [sp,#12]
      400618:       b9400be0        ldr     w0, [sp,#8]
      40061c:       0b000020        add     w0, w1, w0
      400620:       910043ff        add     sp, sp, #0x10
      400624:       d65f03c0        ret
    0000000000400628 <test_sub>:
      400628:       d10043ff        sub     sp, sp, #0x10
      40062c:       b9000fe0        str     w0, [sp,#12]
      400630:       b9000be1        str     w1, [sp,#8]
      400634:       b9400fe1        ldr     w1, [sp,#12]
      400638:       b9400be0        ldr     w0, [sp,#8]
      40063c:       4b000020        sub     w0, w1, w0
      400640:       910043ff        add     sp, sp, #0x10
      400644:       d65f03c0        ret
    0000000000400648 <main>:
      400648:       a9bd7bfd        stp     x29, x30, [sp,#-48]!    	#	将fp,lr寄存器进栈
      40064c:       910003fd        mov     x29, sp						#	将sp寄存器赋值给fd。fp相当于ebp;
      400650:       b9002fbf        str     wzr, [x29,#44]
      400654:       52800020        mov     w0, #0x1                        // #1
      400658:       b9002ba0        str     w0, [x29,#40]
      40065c:       b9402ba1        ldr     w1, [x29,#40]
      400660:       b9402fa0        ldr     w0, [x29,#44]
      400664:       97ffffe9        bl      400608 <test_add>
      400668:       b90027a0        str     w0, [x29,#36]
      40066c:       b9402ba1        ldr     w1, [x29,#40]
      400670:       b9402fa0        ldr     w0, [x29,#44]
      400674:       97ffffe5        bl      400608 <test_add>
      400678:       b90023a0        str     w0, [x29,#32]
      40067c:       b9402ba1        ldr     w1, [x29,#40]
      400680:       b9402fa0        ldr     w0, [x29,#44]
      400684:       97ffffe1        bl      400608 <test_add>
      400688:       b9001fa0        str     w0, [x29,#28]
      40068c:       b9402ba1        ldr     w1, [x29,#40]
      400690:       b9402fa0        ldr     w0, [x29,#44]
      400694:       97ffffdd        bl      400608 <test_add>
      400698:       b9001ba0        str     w0, [x29,#24]
      40069c:       b9402ba1        ldr     w1, [x29,#40]
    
    ##lr寄存器
    (gdb) info registers
    x0             0x0      0
    x1             0x1      1
    x2             0xfffffffff488   281474976707720
    x3             0x400648 4195912
    x4             0x0      0
    x5             0x0      0
    x6             0xfffffffff470   281474976707696
    x7             0x40     64
    x8             0xffffffffffffffff       -1
    x9             0x3ffff  262143
    x10            0x101010101010101        72340172838076673
    x11            0x40     64
    x12            0xffffbf6f2038   281473893474360
    x13            0xffffbf6fefa8   281473893527464
    x14            0x402    1026
    x15            0x2      2
    x16            0xffffbf568040   281473891860544
    x17            0x410a08 4262408
    x18            0xfffffffff260   281474976707168
    x19            0x4006d0 4196048
    x20            0x0      0
    x21            0x0      0
    x22            0x0      0
    x23            0x0      0
    x24            0x0      0
    x25            0x0      0
    x26            0x0      0
    x27            0x0      0
    x28            0x0      0
    x29            0xfffffffff300   281474976707328
    x30            0x400668 4195944
    sp             0xfffffffff2f0   0xfffffffff2f0
    pc             0x400614 0x400614 <test_add+12>
    cpsr           0x60000000       1610612736
    fpsr           0x0      0
    fpcr           0x0      0
    

    异常指令

    svc:arm上实现系统调用的指令
    Eg:系统调用read的系统调用为63,通过x8寄存器传入
    在这里插入图片描述

    ARM32

    寄存器

    • r0 - r15:共16个通用寄存器,均为32bit
    • FP:r11充当,栈帧寄存器
    • sp:r13充当,堆栈指针寄存器
    • LR:r14充当,保存函数返回后执行的下一条指令地址寄存器
    • PC:r15充当,程序计数器
    • Cpsr:状态寄存器

    gcc编译器属性

    1. attribute((naked))

    GCC6.1+版本支持:[Feature](https://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg509509.html)
    

    Arm官方说明

    展开全文
  • ARM汇编指令详解

    千次阅读 2020-08-27 17:40:37
    ARM指令集(32-bit) Thumb指令集(16-bit) Thunmb指令集(16&32bit)不考虑 工作模式 种类:七种 非特权模式(Normal:普通模式) User(用户模式):非特权模式,大部分时候在这个模式下工作 特权模式...

    ARM的编程模式和七种模式

    基本设定

    • 架构(32位)
      • 约定
        • Byte(字节):8bits
        • Halfword(半字) :16 bits (2 byte)
        • Word(字):32bits(4 byte)
    • 指令集
      • ARM指令集(32-bit)
      • Thumb指令集(16-bit)
      • Thunmb指令集(16&32bit)不考虑

    工作模式

    • 种类:七种
    • 非特权模式(Normal:普通模式)
      • User(用户模式):非特权模式,大部分时候在这个模式下工作
    • 特权模式(Privilege:特权模式)
      • FIQ(快速中断模式):当一个高优先级(fast)中断产生时将会进入这种模式
      • IRQ(普通中断模式):当一个低优先级(normal)中断产生时进入这种模式
      • SVC(管理模式):当复位或软中断指令执行时进入
      • Abt(数据访问终止模式):当存取异常时进入
      • und(未定义指令终止模式):当执行未定义指令进入
      • sys(系统模式):使用和User模式相同的寄存器的特权模式

    Privilege除了System模式外,其他5种为异常模式

    各种模式的切换,程序员通过代码切换,(CPSR寄存器);也可以CPU在某些情况下自动切换(中断或者按复位键)

    • 为什么要有这么多模式?

      操作系统有安全级别要求,多模式为了方便操作系统多种角色安全等级需求

    ARM寄存器组织

    • ARM 处理器有 37 个 32 位长的寄存器。

      • 1 个用作 PC(程序指针)。
      • 1 个用作 CPSR(程序状态寄存器)。
      • 5 个用作 SPSR(备份程序状态寄存器)。
      • 30 个用作通用寄存器。

    在这里插入图片描述

    注意:System模式使用user模式寄存器集

    • CPSR程序状态寄存器

    在这里插入图片描述

    • 条件位

      • N:Negative result from ALU (ALU运算时负结果则置1)
      • Z:Zero result from ALU (ALU运算时零结果则置1)
      • C:ALU operation Carried out(进位标志位则置1)
      • V:ALU operation Carried out(溢出是则置1)
    • Mode位(理论上可以有32种模式)

      • 实际ARM只有7种工作模式(每种模式值可查)
    • T位(处理器状态控制位)

      • T = 0:处理器处于ARM状态(默认)

      • T = 1:处理器处于Thumb状态

    • 中断禁止位:

      • I = 1:禁止 IRQ

      • F = 1:禁止FIQ(快速中断)

    ARM异常向量表

    • 异常:正常工作之外的流程都叫异常,中断是异常的一种。

      异常会打断正在执行的工作,并且一般我们希望异常处理完成后继续回来执行原来的工作。

    • 异常向量表

      • 所有的CPU都有异常向量表,这是CPU设计时就设定好的,是硬件决定的。
      • 当异常发生时,CPU会自动动作(PC跳转到异常向量处处理异常,有时伴有一些辅助动作)。
      • 异常向量表是硬件向软件提供的处理异常的支持。

    在这里插入图片描述

    • 异常处理机制(处理过程)

      • 产生异常时,ARM内核

        1. 拷贝 CPSR 到 SPSR_
        2. 设置适当的CPSR位
          • 改变处理器状态进入 ARM 态
          • 改变处理器模式进入相应的异常模式
          • 设置中断禁止位禁止相应中断 (如果需要)
        3. 保存返回地址到 LR_(R14)
        4. 设置 PC 为相应的异常向量
      • 从异常返回时

        1. 从 SPSR_恢复CPSR
        2. 从LR_恢复PC

        注意:这些操作只能在 ARM 态执行。

    异常处理中有一些是硬件自动做的,有一些是程序员需要自己做的。需要搞清楚哪些是需要自己做的,才知道如何写代码。
    以上说的是CPU设计时提供的异常向量表,一般成为一级向量表。有些CPU为了支持多个中断,还会提供二级中断向量表,处理思路类似于这里说的一级中断向量表。
    

    ARM汇编指令集

    • 指令与伪指令(汇编)

      • 指令:指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。
      • 伪指令:伪指令本质上不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。
    • 两种风格

      • ARM官方的指令风格:指令一般用大写,一般用于Windows的开发环境(ADS,MDK等)如: LDR R0, [R1]。
      • GNU风格:指令一般用小写字母、linux中常用。如:ldr r0, [r1]。
    • ARM汇编特点

      1. LDR/STR架构
        • ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内存中内容加载入CPU中通用寄存器中才能被CPU处理。
        • ldr(load register)指令将内存内容加载入通用寄存器。
        • str(store register)指令将寄存器内容存入内存空间中。
        • ldr/str组合用来实现 ARM CPU和内存数据交换
      2. 八种寻址方式
        • 寄存器寻址 mov r1, r2 r2的值赋值给r1

        • 立即寻址 mov r0, #0xFF00 #后面的数值直接赋值给r0

        • ​ 寄存器移位寻址 mov r0, r1, lsl #3(书本无) r1中的数值左移三位,然后赋值给r0(就是乘于8)

        • 寄存器间接寻址 ldr r1, [r2] 类似于指针,r2中存操作数的地址,[]类似于解引用

        • 基址变址寻址 ldr r1, [r2, #4] r2为基址,r2里面的地址加4,这个地址存的值读到寄存器中

        • 多寄存器寻址 ldmia r1!, {r2-r7, r12} r1中的8个地址读到r2-r7和r12中(类似于数值中的8个元素)

        • 堆栈寻址 stmfd sp!, {r2-r7, lr} 将寄存器列表中的寄存器(R2到R7,lr)存入堆栈

        • 相对寻址 beq flag

          ​ flag:

      3. 指令后缀

        同一指令经常附带不同后缀,变成不同的指令。经常使用的后缀有:

        • B(byte)功能不变,操作长度变为8位。

        • H(half word)功能不变,长度变为16位。

        • !如果指令地址表达式中不含“!”后缀,则基址寄存器中的地址不会发生变化,指令中含有则变化,变化结果如下:基址寄存器中的值(指令执行后)=指令执行前的值+地址偏移量

          注意:

        • “!”后缀必须紧跟在地址表达式后面,而地址表达式要有明确的地址偏移量。

        • “!”后缀不能用于R15(PC)的后面

        • 当用于单个寄存器后面时,必须确性这个寄存器有隐性的偏移量,eg:“STMDB SP!,{R3,R5,R7}”此时地址基址寄存器SP的隐性偏移量是4。

        • S(signed)功能不变,操作数变为有符号,如 ldr ldrb ldrh ldrsb ldrsh。

        • S(S标志)功能不变,影响CPSR标志位,如 mov和movs movs r0, #0。指令中使用“S”后缀,指令执行后状态寄存器的条件标志位将被刷新;不使用“S”后缀时,指令执行后状态寄存器的条件标志位不会发生变化。此标志经常用于对条件进行测试,例如:是否溢出,是否进位等;根据这些变化,就可以进行一些判断,是否大于,是否相等,从而可能影响指令执行顺序。

        两个 S 用于不同的指令,名称相同,但是在不同的指令结合却有不同的作用

      4. 条件执行后缀

    在这里插入图片描述

     **注意**
    
     - 条件后缀是否成立,不是取决于本句代码,而是取决于这句代码之前的代码运行后的结果。
     - 条件后缀决定了本句代码是否被执行,而不会影响上一句和下一句代码是否被执行。
    
    1. 多指令流水线
      • 为增加处理器指令流的速度,ARM使用多级流水线.,下图为3级流水线工作原理示意图。(ARM11为8级),当处理器执行简单的数据处理指令时,流水线使得平均每个时钟周期能完成 1 条指令。但 1 条指令需要 3个时钟周期来完成,因此,有 3 个时钟周期的延时( latency),但吞吐率( throughput)是每个周期一条指令。

    在这里插入图片描述

     **注意**:PC指向正被取指的指令,而非正在执行的指令
    
    • 常用ARM指令

      1. 数据处理指令
        • 数据传输指令 mov mvn
        • 算术指令 add sub rsb adc sbc rsc
        • 逻辑指令 and orr eor bic
        • 比较指令 cmp cmn tst teq
        • 乘法指令 mvl mla umull umlal smull smlal
        • 前导零计数 clz
      2. CPSR访问指令
        • mrs & msr
          1. mrs用来读psr,msr用来写psr
          2. CPSR寄存器比较特殊,需要专门的指令访问,这就是mrs和msr。
      3. 跳转(分支)指令
        • b & bl & bx
          1. b 直接跳转(就没打开算返回)
          2. bl branch and link,跳转前把返回地址放入lr中,以便返回,以便用于函数调用
          3. bx跳转同时切换到ARM模式,一般用于异常处理的跳转。
      4. 访存指令
        • ldr/str & ldm/stm & swp

          1. 单个字/半字/字节访问 ldr/str

          2. 多字批量访问 ldm/stm

            swp r1, r2, [r0] 将 r0 所指向的存储器中的字数据传输到 r1,同时将 r2中的字数据传输到 r0 所指向的内存单元。

            swp r1, r1, [r0] 该指令完成将 r0 所执行的存储器中的子数据与 r1 中的字数据互换。

      5. ARM汇编中的立即数

        ARM指令都是32位,除了指令标记和操作标记外,本身只能附带很少位数的立即数。因此立即数有合法和非法之分。

        • 合法立即数:并不是所有的 32-bit 立即数都是可以使用的合法立即数。只有那些通过将一个 8-bit 的立即数循环右移偶数位可以得到的立即数才可以在指令中使用。(了解即可

          注意:加载立即数一般采用伪指令 ldr, 编译器会自动处理非法立即数,这里了解即可,

      6. 软中断指令

        • swi(software interrupt)

          软中断指令用来实现操作系统中系统调用(真实使用场景用处不大,仅作学习使用)

      7. 协处理器(CP15)操作指令

        CP15,即通常所说的系统控制协处理器( System Control Coprocesssor)。 SoC内部另一处理核心,协助主CPU实现某些功能,被主CPU调用执行一定任务。

        ARM 处理器支持 16 个协处理器。在程序执行过程中,每个协处理器忽略属于 ARM 处理器和其他协处理器的指令。当一个协处理器硬件不能执行属于它的协处理器指令时,将产生一个未定义指令异常中断,在该异常中断处理程序中,可以通过软件模拟该硬件操作。(不必深究

        • mcr & mrc
          1. mrc用于读取CP15中的寄存器
          2. mcr用于写入CP15中的寄存器
        • 使用方法
          • mcr{} p15, <opcode_1>, , , , {<opcode_2>}
            1. opcode_1:对于cp15永远为0
            2. Rd:ARM的普通寄存器
            3. Crn:cp15的寄存器,合法值是c0~c15
            4. Crm:cp15的寄存器,一般均设为c0
            5. opcode_2:一般省略或为0
        • 举例
          • mrc p15, 0, r0, c1, c0, 0 该指令将协处理器 p15 的寄存器中的数据传送到ARM处理器的寄存器中
          • mcr p15, 0, r0, c1, c0, 0 该指令将ARM处理器寄存器 r0 中的数据传送到协处理器 p15 的寄存器 c1 和 c0 中。

        协处理器的学习要点

        不必深究

        只看一般用法,不详细区分参数细节,否则会陷入很多复杂未知中。关键在于理解,而不在于记住。

      8. 批量数据加载存储指令(LDM/STM与栈的处理)
        • 为什么需要多寄存器访问指令

          ldr/str每周期只能访问4字节内存,如果需要批量读取、写入内存时太慢,解决方案是stm/ldm

        • stm/ldm
          1. ldm(load register mutiple) 加载多个寄存器
          2. stm(store register mutiple) 存储多个寄存器

          举例:

          stmia sp, {r0 - r12}
          将r0存入sp指向的内存处(假设为0x30001000);然后地址+4(即指向0x30001004),将r1存入该地址;然后地址再+4(指向0x30001008),将r2存入该地址······直到r12内容放(0x3001030),指令完成。
          一个访存周期同时完成13个寄存器的读写

        • 八种后缀
          • ia(increase after)先传输,再地址+4
          • ib(increase before)先地址+4,再传输
          • da(decrease after)先传输,再地址-4
          • db(decrease before)先地址-4,再传输
          • fd(full decrease)满递减堆栈
          • ed(empty decrease)空递减堆栈
          • fa(·······) 满递增堆栈
          • ea(·······)空递增堆栈
        • 四种栈
          • 空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出
          • 满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针
          • 增栈:栈指针移动时向地址增加的方向移动的栈
          • 减栈:栈指针移动时向地址减小的方向移动的栈
        • 后缀符号的作用
          1. 的作用

            ldmia r0, {r2 - r3}
            ldmia r0!, {r2 - r3}

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

          2. ^ 的作用

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

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

        总结:批量读取或写入内存时要用ldm/stm指令各种后缀以理解为主,不需记忆,最常见的是stmia(空堆栈递增)stmfd(满堆栈递减)
        谨记:操作栈时使用相同的后缀(LDM/STM)就不会出错,不管是满栈还是空栈、增栈还是减栈。

    ARM汇编伪指令

    1. 伪指令的意义

      • 伪指令不是指令,伪指令和指令的根本区别是经过编译后会不会生成机器码。
      • 伪指令的意义在于指导编译过程。
      • 伪指令是和具体的编译器相关的,我们使用gnu工具链,因此学习gnu环境下的汇编伪指令。
    2. GUN汇编中的一些符号

      • @ 用来做注释。可以在行首也可以在代码后面同一行直接跟,和C语言中//类似。
      • # 做注释,一般放在行首,表示这一行都是注释而不是代码。
      • :以冒号结尾的是标号。
      • . 点号在gnu汇编中表示当前指令的地址。
      • # 立即数前面要加#或 $,表示这是个立即数。
    3. 常用GUN伪指令
      • .global _start @ 给_start外部链接属性
      • .section .text @ 指定当前段为代码段
      • .ascii .byte .short .long .word
      • .quad .float .string @ 定义数据
      • .align 4 @ 以16字节对齐
      • .balignl 16 0xabcdefgh @ 16字节对齐填充
      • .equ @ 类似于C中宏定义
    4. 偶尔用到的GUN伪指令
      • .end @标识文件结束
      • .include @ 头文件包含
      • .arm / .code32 @声明以下为arm指令
      • .thumb / .code16 @声明以下为thubm指令
    5. 最重要的几个伪指令
      • ldr 大范围的地址加载指令
      • adr 小范围的地址加载指令
      • adrl 中等范围的地址加载指令
      • nop 空操作
      adr与ldr
      • adr编译时会被1条sub或add指令替代,而ldr编译时会被一条mov指令替代或者文字池方式处理;
      • adr总是以PC为基准来表示地址,因此指令本身和运行地址有关,可以用来检测程序当前的运行地址
      • 在哪里
      • ldr加载的地址和链接时给定的地址有关,由链接脚本决定。

      ARM中有一个ldr指令,还有一个ldr伪指令

      一般都使用ldr伪指令而不用ldr指令

    展开全文
  • ARM汇编指令集 ARM处理器的指令集可以分为跳转指令、数据处理指令、程序状态寄存器(PSR)处理指令、加载/存储指令、协处理器指令和异常产生指令6大指令........
  • 某度文库同名下下来文件
  • arm汇编指令chm

    2018-07-06 21:46:58
    关于ARM方面的硬件或软件问题,可以在这里找到答案 ,如果您希望增加嵌入式软件开发经验,这里有很多不错的资料
  • ARM汇编指令

    2018-12-05 18:04:24
    ARM汇编指令,学习ARM汇编可以下载看看,总结了许多汇编指令
  • arm汇编指令集大全

    2018-09-12 08:52:23
    1 ARM 汇编指令集 一、 跳转指令 跳转指令用于实现程序流程的跳转, 在 ARM 程序中有两种方法可以实现程序流程的跳转: Ⅰ.使用专门的跳转指令。 Ⅱ.直接向程序计数器 PC 写入跳转地址值。 通过向程序计数器 PC 写入...
  • ARM汇编指令集汇总

    万次阅读 多人点赞 2018-11-09 14:44:37
    ARM汇编指令集汇总 作者:毛茏玮 / Saint 掘金:https://juejin.im/user/5aa1f89b6fb9a028bb18966a 微博:https://weibo.com/5458277467/profile?topnav=1&amp;wvr=6&amp;is_all=1 GitHub:github....

    在这里插入图片描述

    ARM汇编指令集汇总

    作者: Saint
    掘金:https://juejin.im/user/5aa1f89b6fb9a028bb18966a
    微博:https://weibo.com/5458277467/profile?topnav=1&wvr=6&is_all=1
    GitHub:github.com/saint-000
    CSDN: https://me.csdn.net/qq_40531974

    今天Saint给大家分享一下对汇编指令代码的汇总。
    在这里插入图片描述
    一.汇编数据处理指令

    1.数据传送指令

    【MOV指令】:它的传送指令只能是把一个寄存器的值(要能用立即数表示)赋给另一个寄存器,或者将一个常量赋给寄存器,将后边的量赋给前边的量。

    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(即乘8)
    MOVS PC, R14	  ;将寄存器R14的值传送到PC中,返回到调用代码并恢复标志位
    

    除了MOV指令外,还有数据取反传送指令MVN。 【MVN指令】

    MVN指令的格式为:
    MVN{条件}{S} 目的寄存器,源操作数
    复制代码
    MVN指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。其中S决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

    指令示例:

    MVN R0,#0   ;将立即数0取反传送到寄存器R0中,完成后R0=-1(有符号位取反)
    

    2.算术运算指令

    (1)【加法指令】:ADD

    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)【带进位的加法指令】:ADC
    ADC指令的格式为:
    ADC{条件}{S} 目的寄存器,操作数1,操作数2

    ADC指令用于把两个操作数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。
    它使用一个进位标志位,这样就可以做比32位大的数的加法,注意不要忘记设置S后缀来更改进位标志。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
    以下指令序列完成两个128位数(此处应为两个四字数相加)的加法,第一个数由高到低存放在寄存器R7~R4,第二个数由高到低存放在寄存器R11~R8,运算结果由高到低存放在寄存器R3~R0:

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

    (3)【减法指令】:SUB
    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)
    

    (4)【带借位减法指令】:SBC
    SBC指令的格式为:
    SBC{条件}{S} 目的寄存器,操作数1,操作数2

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

    SUBS  R0,R1,R2           ;R0 = R1 - R2 - !C,并根据结果设置CPSR的进位标志位
    

    3.比较指令
    (1)【直接比较指令】:CMP
    CMP指令的格式为:
    CMP{条件} 操作数1,操作数2

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

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

    (2)【负数比较指令】:CMN
    CMN指令的格式为:
    CMN{条件} 操作数1,操作数2

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

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

    4.逻辑运算指令
    (1)【逻辑与指令】:AND
    AND指令的格式为:
    AND{条件}{S} 目的寄存器,操作数1,操作数2

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

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

    (2)【逻辑或指令】:ORR
    ORR指令的格式为:
    ORR{条件}{S} 目的寄存器,操作数1,操作数2

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

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

    (3)【逻辑异或指令】:EOR
    EOR指令的格式为:
    EOR{条件}{S} 目的寄存器,操作数1,操作数2

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

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

    (4)【位清零指令】:BIC
    BIC指令的格式为:
    BIC{条件}{S} 目的寄存器,操作数1,操作数2

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

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

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

    TST R1,#%1  ;用于测试在寄存器R1中是否设置了最低位(%表示二进制数)
    TST R1,#0xffe  ;将寄存器R1的值与立即数0xffe按位与,并根据结果设置CPSR的标志位
    

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

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

    6.乘法指令
    在这里插入图片描述

    二.汇编转移指令
    【跳转指令】
    跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:
    — 使用专门的跳转指令。
    — 直接向程序计数器PC写入跳转地址值。
    通过向程序计数器PC写入跳转地址值,可以实现在4GB的地址空间中的任意跳转,在跳转之前结合使用MOV LR,PC等类似指令,可以保存将来的返回地址值,从而实现在4GB连续的线性地址空间的子程序调用。
    ARM指令集中的跳转指令可以完成从当前指令向前或向后的32MB的地址空间的跳转,包括以下4条指令:

     — B 跳转指令
    — BL 带返回的跳转指令
    — BLX 带返回和状态切换的跳转指令
    — BX 带状态切换的跳转指令
    

    1、【B指令】
    B指令的格式为:
    B{条件} 目标地址
    B指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。
    它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB的地址空间)。以下指令:

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

    2、【BL指令】
    BL指令的格式为:
    BL{条件} 目标地址
    BL 是另一个跳转指令,但跳转之前,会在寄存器R14中保存PC的当前内容,因此,可以通过将R14 的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。
    该指令是实现子程序调用的一个基本但常用的手段。以下指令:

    BL Label  ;当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中
    

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

    4、【BX指令】
    BX指令的格式为:
    BX{条件} 目标地址
    BX指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。

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

    MRS R0,CPSR   ;传送CPSR的内容到R0
    MRS R0,SPSR   ;传送SPSR的内容到R0
    

    2、【MSR指令】
    MSR指令的格式为:
    MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操作数
    MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域:

    位[31:24]为条件标志位域,用f表示;
    位[23:16]为状态位域,用s表示;
    位[15:8]为扩展位域,用x表示;
    位[7:0]为控制位域,用c表示;
    

    该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域。
    指令示例:

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

    四.汇编加载/存储指令
    ARM微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。常用的加载存储指令如下:
    在这里插入图片描述

    1、【LDR指令】
    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。
    

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

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

    3、【LDRH指令】
    LDRH指令的格式为:
    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位清零。
    

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

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

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

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

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

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

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

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

    【LDM(或STM)指令】
    LDM(或STM)指令的格式为:

    LDM(或STM){条件}{类型} 基址寄存器{!},寄存器列表{∧}
    

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

    IA 每次传送后地址加1;
    IB 每次传送前地址加1;
    DA 每次传送后地址减1;
    DB 每次传送前地址减1;
    FD 满递减堆栈;
    ED 空递减堆栈;
    FA 满递增堆栈;
    EA 空递增堆栈;
    

    {!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
    基址寄存器不允许为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,LR)。
    

    五.汇编异常产生指令
    1、【SWI指令】
    SWI指令的格式为:

    SWI{条件} 24位的立即数
    

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

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

    2、【BKPT指令】
    BKPT指令的格式为:

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

    六.汇编伪代码

    1.【AREA】一个汇编程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段,因此在汇编程序的开头,我们一般的语句会用到AREA。

    语法格式:AREA 段名 属性 1 ,属性 2 ,....  
    

    AREA 伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用 “ | ” 括起来,如 |1_test| 。
    属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:

    — CODE 属性:用于定义代码段,默认为 READONLY 。            
    — DATA 属性:用于定义数据段,默认为 READWRITE 。      
    — READONLY 属性:指定本段为只读,代码段默认为 READONLY 。          
    — READWRITE 属性:指定本段为可读可写,数据段的默认属性为 READWRITE 。  
     — ALIGN 属性:使用方式为ALIGN 表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为 0 ~31,相应的对齐方式为2表达式次方。
     — COMMON 属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的 COMMON 段共享同一段存储单元。
    

    使用示例:

    AREA Init , CODE , READONLY ;该伪指令定义了一个代码段,段名为 Init ,属性为只读。 
    

    2、【ALIGN】语法格式:

    ALIGN { 表达式 { ,偏移量 }}    
    

    ALIGN 伪指令可通过添加填充字节的方式,使当前位置满足一定的对其方式。其中,表达式的值用于指定对齐方式,可能的取值为2的幂,如 1 、2 、4 、8 、16 等。
    若未指定表达式,则将当前位置对齐到下一个字的位置。偏移量也为一个数字表达式,若使用该字段,则当前位置的对齐方式为:2的表达式次幂+偏移量。            
    使用示例:

    AREA Init,CODE ,READONLY,ALIEN=3;指定后面的指令为 8 字节对齐。      
    ....
    ;指令序列  
    .... 
    END      
      
    

    3、【CODE16、CODE32】            
    语法格式:CODE16 (或 CODE32 )

    CODE16 伪指令通知编译器,其后的指令序列为 16 位的 Thumb 指令。      
    CODE32 伪指令通知编译器,其后的指令序列为 32 位的 ARM 指令。            
    若在汇编源程序中同时包含 ARM 指令和 Thumb 指令时,可用 CODE16 伪指令通知编译器其后的指令序列为 16 位的 Thumb 指令, CODE32 伪指令通知编译器其后的指令序列为 32 位的 ARM 指令。
    因此,在使用 ARM 指令和 Thumb 指令混合编程的代码里,可用这两条伪指令进行切换,但注意他们只通知编译器其后指令的类型,并不能对处理器进行状态的切换。            
    使用示例:

    AREA Init ,CODE ,READONLY            
    ....      
    CODE32 ;通知编译器其后的指令为 32 位的 ARM 指令            
    LDR R0,=NEXT+1 ;将跳转地址放入寄存器 R0      
    BX R0 ;程序跳转到新的位置执行,并将处理器切换到 Thumb 工作状态      
    ....     
    CODE16 ;通知编译器其后的指令为 16 位的 Thumb 指令            
    NEXT LDR R3,=0x3FF            
    ....     
    END ;程序结束         
    

    4、【ENTRY】            
    语法格式:ENTRY      
    ENTRY 伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个 ENTRY (也可以有多个,当有多个 ENTRY 时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个 ENTRY (可以没有)。            
    使用示例:

    AREA Init , CODE , READONLY            
    ENTRY ;指定应用程序的入口点
    .....   
    

    5、【END】            
    语法格式:END      
    END 伪指令用于通知编译器已经到了源程序的结尾。           
    使用示例:

    AREA Init , CODE , READONLY            
    ......     
    END ;指定应用程序的结尾
    
    展开全文
  • 常用的ARM汇编指令总结

    万次阅读 多人点赞 2018-07-13 10:28:50
    本人从事软件开发相关的工作,平时主要用c语言撸代码,前段时间因工作需要,接触到了ARM架构下的汇编指令,之前学过51单片机的汇编指令,早已经还给老师了,且ARM汇编指令与51的也有很大差别。故搞ARM汇编指令时,...

    第一次写博客,请各路大神多多关照。

    本人从事软件开发相关的工作,平时主要用c语言撸代码,前段时间因工作需要,接触到了ARM架构下的汇编指令,之前学过51单片机的汇编指令,早已经还给老师了,且ARM汇编指令与51的也有很大差别。故搞ARM汇编指令时,遇到不懂的就问度娘,并总结了下来,希望对从事相关行业的同仁有所帮助。闲话不多说,上干货。

    1、  IMPORT和EXPORT

    IMPORT ,定义表示这是一个外部变量的标号,不是在本程序定义的

    EXPORT ,表示本程序里面用到的变量提供给其他模块调用的。

    以上两个在汇编和C语言混合编程的时候用到。

     

    2、AREA

    语法格式:    
        AREA 段名 属性1 ,属性2 ,……    
        AREA伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“|”括起来,如:|1_test|。    
        属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:    
        — CODE 属性:用于定义代码段,默认为READONLY 。    
        — DATA 属性:用于定义数据段,默认为READWRITE 。    
        — READONLY 属性:指定本段为只读,代码段默认为READONLY 。    
        — READWRITE 属性:指定本段为可读可写,数据段的默认属性为READWRITE 。    
        — ALIGN 属性:使用方式为ALIGN表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。    
        — COMMON 属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元。 
        一个汇编语言程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段。    
        使用示例:    
        AREA Init ,CODE ,READONLY ;   该伪指令定义了一个代码段,段名为Init ,属性为只读。

     

     

    3、LDR、LDRB、LDRH

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

    —  LDR     字数据加载指令

    — LDRB    字节数据加载指令

    —  LDRH    半字数据加载指令

    1)     LDR指令有两种用法:

    a、ldr加载指令
    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。”

    ARM是RISC结构,数据从内存到CPU间的移劢只能通过L/S指令来完成,也就是ldr/str指令。  
    比如想把数据从内存中某处读取到寄存器中,只能使用ldr 
    比如: 
    ldr r0, 0x12345678 
    就是把0x12345678返个地址中的值存放到r0中。

     

    b、ldr伪指令
    ARM指令集中,LDR通常都是作加载指令的,但是它也可以作伪指令。
    LDR伪指令的形式是“LDRRn,=expr”。
    例子:
    COUNT EQU       0x40003100
    ……
    LDR       R1,=COUNT
    MOV      R0,#0
    STR       R0,[R1]

    COUNT是我们定义的一个变量,地址为0x40003100。这种定义方法在汇编语言中是很常见的,如果使用过单片机的话,应该都熟悉这种用法。
    LDR       R1,=COUNT是将COUNT这个变量的地址,也就是0x40003100放到R1中。
    MOV      R0,#0是将立即数0放到R0中。最后一句STR     R0,[R1]是一个典型的存储指令,将R0中的值放到以R1中的值为地址的存储单元去。实际就是将0放到地址为0x40003100的存储单元中去。

    下面还有一个例子
    ;将COUNT的值赋给R0
    LDR       R1,=COUNT
    LDR       R0,[R1]
    LDR       R1,=COUNT这条伪指令,是怎样完成将COUNT的地址赋给R1,有兴趣的可以看它编译后的结果。这条指令实际上会编译成一条LDR指令和一条DCD伪指令。

    2)     LDRB指令

    LDRB指令的格式为:

    LDR{条件}B 目的寄存器,<存储器地址>

    LDRB指令用于将存储器中低8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的数据被当作目的地址,从而可以实现程序流程的跳转。

    指令示例:

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

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

     

    3)     LDRH指令

    LDRH指令的格式为:

    LDR{条件}H 目的寄存器,<存储器地址>

    LDRH指令用于将存储器中低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位清零。

     

    4、SUB

    (Subtraction)

    SUB{条件}{S} , , dest = op_1 - op_2

    SUB 用操作数 one 减去操作数 two,把结果放置到目的寄存器中。操作数 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)

    减法可以在有符号和无符号数上进行。

    ps:带进位的减法SBC

     

    5、CMP 、TST、BNE、BEQ

    BNE和BEQ经常与CMP 或TST搭配使用。

    在讲解这几个指令前,先介绍下CPSR这个寄存器,因为CMP和TST指令会对CPSR中的某些位产生影响,而BNE和BEQ指令的动作正是与CPSR中被影响的这些位有关。

    CMP:

    假设现在AX寄存器中的数是0002H,BX寄存器中的数是0003H。执行的指令是:CMP AX, BX

    执行这条指令时,先做用AX中的数减去BX中的数的减法运算。列出二进制运算式子:
           0000 0000 0000 0010

    -0000 0000 0000 0011
    _________________________________
    (借位1) 1111 11111111 1111

    所以,运算结果是 0FFFFH

    根据这个结果,各标志位将会被分别设置成以下值:
    CF=1,因为有借位   // CF即为上述CPSR中的C
    OF=0,未溢出           // OF即为上述CPSR中的V
    SF=1,结果是负数   // SF即为上述CPSR中的N
    ZF=0,结果不全是零    // ZF即为上述CPSR中的Z

    还有AF, PF等也会相应地被设置。

    CMP 比较指令做了减法运算以后,根据运算结果设置了各个标志位。

    标志位设置过以后,0FFFFH这个减法运算的结果就没用了,它被丢弃,不保存。

    执行过了CMP指令以后,除了CF,ZF,OF,SF,等各个标志位变化外,其它的数据不变。

    对照普通的减法指令 SUB AX, BX,它们的区别就在于:
    SUB指令执行过以后,原来AX中的被减数丢了,被换成了减法的结果。
    CMP指令执行过以后,被减数、减数都保持原样不变。

     

    TST:

    逻辑处理指令,用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位与运算,并根据运算结果更新CPSR中条件标志位的值。当前运算结果为非0,则Z=0;当前运算结果为0,则Z=1

    BNE:数据跳转指令,标志寄存器中Z标志位等于零时,跳转到BNE后标签处。特别要注意这里,通常我们说BNE是“不相等”或“不为零”时跳转,此处的“不相等”或“不为零”是指比较结果不相等或做减法不为零,不是指Z标志位。比较结果不相等或做减法不为零时,Z标志位是等于零的。

    BEQ:数据跳转指令,标志寄存器中Z标志位不等于零时, 跳转到BEQ后标签处

     

    6、STR、STRB、STRH指令

    — STR     字数据存储指令

    — STRB    字节数据存储指令

    — STRH    半字数据存储指令

    A、STR指令的格式为:

    STR{条件} 源寄存器,<存储器地址>

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

    指令示例:

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

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

     

    B、STRB指令的格式为:

    STR{条件}B 源寄存器,<存储器地址>

    STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。

    指令示例:

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

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

     

    C、STRH指令的格式为:

    STR{条件}H 源寄存器,<存储器地址>

    STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位。

    指令示例:

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

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

     

     

    7、跳转指令B、BL、BX、BLX 和 BXJ的区别

    跳转指令用于实现程序流程的跳转,在 ARM 程序中有两种方法可以实现程序流程的跳转:

    (1) 使用专门的跳转指令。

    (2) 直接向程序计数器 PC 写入跳转地址值。

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

    MOV LR , PC

    等类似指令,可以保存下一条指令地址作为将来的返回地址值,从而实现在 4GB 连续的线性地址空间的子程序调用。

    专门的跳转指令:

    B、BL、BX、BLX 和 BXJ

    跳转、带链接跳转(带返回的跳转)、跳转并切换指令集、带链接跳转并切换指令集(带返回的跳转并切换指令集)、跳转并转换到 Jazelle 状态。

    a)     、 B 指令

    B 指令的格式为:

    B{条件} 目标地址

    B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间)。以下指令:

    B Label ;程序无条件跳转到标号 Label 处执行

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

    BEQ Label

    b)     、 BL 指令

    BL 指令的格式为:

    BL{条件} 目标地址

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

    BL Label ;当程序无条件跳转到标号 Label 处执行时,同时将当前的 PC 值保存到 R14 中

    c)     、 BLX 指令

    BLX 指令的格式为:

    BLX 目标地址

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

    同时,子程序的返回可以通过将寄存器R14 值复制到PC 中来完成。

    d)     、 BX 指令 

    BX 指令的格式为:

    BX{条件} 目标地址

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

     

    语法

    op1{cond}{.W}<wbr />label
    op2{cond} <wbr />Rm

    其中:

    op1

    是下列项之一:

    B:跳转;BL:带链接跳转;BLX:带链接跳转并切换指令集。

    op2

    是下列项之一:

    BX:跳转并切换指令集;BLX:带链接跳转并切换指令集;

    BXJ:跳转并转换为Jazelle执行。

    cond:是一个可选的条件代码。 cond 不能用于此指令的所有形式。

    .W:是一个可选的指令宽度说明符,用于强制要求在 Thumb-2 中使用 32 位 B 指令。

    label:是一个程序相对的表达式。

    Rm:是一个寄存器,包含要跳转到的目标地址。

     

    所有这些指令均会引发跳转,或跳转到 label,或跳转到包含在Rm中的地址处。此外:

    BL 和 BLSTMCSIAX 指令可将下一个指令的地址复制到 lr(r14,链接寄存器)中。

    BX 和 BLX 指令可将处理器的状态从 ARM 更改为 Thumb,或从 Thumb 更改为 ARM。

    BLX label 无论何种情况,始终会更改处理器的状态。

    BX Rm 和 BLX Rm 可从 Rm 的位 [0] 推算出目标状态:

    如果 Rm 的位 [0] 为 0,则处理器的状态会更改为(或保持在)ARM 状态

    如果 Rm 的位 [0] 为 1,则处理器的状态会更改为(或保持在)Thumb 状态。

    BXJ 指令会将处理器的状态更改为 Jazelle

     

    8、STMFD和LDMFD指令

    这两条指令分别是入栈和出栈的意思,因此先来讲一下堆栈的相关概念:

    a)     满堆栈:即入栈后堆栈指针sp指向最后一个入栈的元素。也就是sp先减一(加一)再入栈。

    b)     空堆栈:即入栈后堆栈指针指向最后一个入栈元素的下一个元素。也就是先入栈sp再减一(或加一)。

    c)     递增堆栈:即堆栈一开始的地址是低地址,向高地址开始递增。就如同一个水杯(假设上面地址大)开口的是大地址,从杯底开始装水。

    d)     递减堆栈:即堆栈一开始的地址是高地址,向低地址开始递增。就如同刚才说的那个水杯,现在开口的是小地址,从大地址开始用。

    有这些类型就可以构成4种不同的堆栈方式,arm的栈一般我们用满堆栈、递减堆栈。

    一开始,看到 STMFD sp!{R0-R5,LR} 这条命令时真是有点疑惑。STMFD的意思是:ST(store 存储) M(multiple 多次)F(full 满堆栈)D(decrease 递减堆栈),合起来就是按满的递减的方式把后面的寄存器里的值都存到sp中。

    STMFD sp!{R0-R5,LR}就是把lr  r5-r0 依次存到sp中,并且sp会在存数据之前自动减一个数据的空间(因为arm栈是递减的)。至于最后一个问题,就是sp后为什么有一个“!”。如果有!号,表示在存入数据后sp会指向最后一个存入的数据的地址,否则sp会把自己的值加到一开始的地址。(就是sp在执行完这条指令之后sp指向的地址不变)。

    例子:STMFD sp!,{r0} ;将r0中的值压入堆栈,压入过程是,由于r0中的值为32位的,首先将sp减去4(因为arm栈是递减的),将r0中的低八位放入sp这个位置,第九位到第十六位放入sp+1的地址,将第十七位到第二十四位放入sp+2的位置,将第二十五位到第三十二位放入sp+3的位置。

    LDMFD sp!,{r2,r3};将堆栈中的内容出栈,出栈过程是,将sp这个位置的值放入r2中的低八位,将sp+1这个位置的值放入r2中的第九位到第十六位,将sp+2这个位置的值放入r2中的第十七位到第二十四位,将sp+3这个位置的值放入r2中的第二十五位到第三十二位;将sp+4这个位置的值放入r3中的低八位,将sp+5这个位置的值放入r3中的第九位到第十六位,将sp+6这个位置的值放入r3中的第十七位到第二十四位,将sp+4这个位置的值放入r3中的第二十五位到第三十二位。最后sp=sp+8。

    此外,STR指令也可以用来入栈:strr1, [sp,#4] ,将r1中的值压入堆栈,压入过程是,由于r1中的值为32位的,将r0中的低八位放入sp+4这个位置,第九位到第十六位放入sp+5的地址,将第十七位到第二十四位放入sp+6的位置,将第二十五位到第三十二位放入sp+7的位置。

     

    9、移位指令(操作)

    a)     LSL(或ASL)操作

    LSL(或ASL)操作的格式为:

    通用寄存器,LSL(或ASL) 操作数     

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

    操作示例

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

    b)     LSR操作

    LSR操作的格式为:

    通用寄存器,LSR 操作数     

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

    操作示例:

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

    c)     ASR操作

    ASR操作的格式为:

    通用寄存器,ASR 操作数     

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

    操作示例:

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

    d)     ROR操作

    ROR操作的格式为:

    通用寄存器,ROR 操作数     

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

    操作示例:

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

    e)     RRX操作

    RRX操作的格式为:

    通用寄存器,RRX 操作数     

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

    操作示例:

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

    f)       SHL和SHR:逻辑移位指令。

    SHL是逻辑左移指令,它的功能为:

    (1)将一个寄存器或内存单元中的数据向左移位;

    (2)将最后移出的一位写入CF中;

    (3)最低位用0补充。

    指令:
    MOV AL,01001000b

    SHL AL,1 ;将AL中数据左移一位

    执行后(AL)=10010000b,CF=0。

    注意:

    如果移动位数大于1时,必须将移动位数放在CL中。

    比如,指令:

    MOV AL,01010001b

    MOV CL,3

    SHL AL,CL

    执行后(AL)=10001000b,因为最后移出的一位是0,所以CF=0。LDRB

    SHR是逻辑右移指令,它和SHL所进行的操作刚好相反。

     

    10、逻辑指令

    a)     AND

    逻辑与操作指令。将operand2 值与寄存器Rn 的值按位作逻辑与操作,结果保存到Rd 中。指令格式如下:
            AND{cond}{S} Rd,Rn,operand2
            AND 指令举例如下:
            ANDS R0,R0,#x01 ;R0=R0&0x01,取出最低位数据
            AND R2,R1,R3 ;R2=R1&R3

    b)     ORR
            逻辑或操作指令。将operand2 的值与寄存器Rn 的值按位作逻辑或操作,结果保存到Rd 中。指令格式如下:
            ORR{cond}{S} Rd,Rn,operand2
            ORR 指令举例如下:
            ORR R0,R0,#x0F ;将R0 的低4 位置1
            MOV R1,R2,LSR #4
            ORR R3,R1,R3,LSL #8 ;使用ORR 指令将近R2 的高8 位数据移入到R3 低8 位中

    c)     EOR
            逻辑异或操作指令。将operand2 的值与寄存器Rn 的值按位作逻辑异或操作,结果保存到Rd 中。指令格式如下:
            EOR{cond}{S}Rd,Rn,operand2
            EOR 指令举例如下:
            EOR R1,R1,#0x0F ;将R1 的低4 位取反
            EOR R2,R1,R0 ;R2=R1^R0
            EORS R0,R5,#0x01 ;将R5 和0x01 进行逻辑异或,结果保存到R0,并影响标志位

     

    11、条件助记符

    ARM汇编指令的基本指令格式如下:

    <opcode>[<cond>][s]<Rd>,<Rn>,[<op2>],其中,[<参数>]可选,指令长度32bit。第一项为操作码,第二项为条件助记符。常用的条件助记符及其含义如下表所示。由指令格式可知,操作码可与条件助记符结合起来一起使用,如MOVEQ,MOVNE,BLS等等,根据下表中条件助记符的含义和操作码的含义,对于上述组合命令也就不难理解了。

    操作码

    条件助记符

    标志

    含义

    0000

    EQ

    Z=1

    相等

    0001

    NE

    Z=0

    不相等

    0010

    CS/HS

    C=1

    无符号数大于或等于

    0011

    CC/LO

    C=0

    无符号数小于

    0100

    MI

    N=1

    负数

    0101

    PL

    N=0

    正数或零

    0110

    VS

    V=1

    溢出

    0111

    VC

    V=0

    没有溢出

    1000

    HI

    C=1,Z=0

    无符号数大于

    1001

    LS

    C=0,Z=1

    无符号数小于或等于

    1010

    GE

    N=V

    有符号数大于或等于

    1011

    LT

    N!=V

    有符号数小于

    1100

    GT

    Z=0,N=V

    有符号数大于

    1101

    LE

    Z=1,N!=V

    有符号数小于或等于

    1110

    AL

    任何

    无条件执行 (指令默认条件)

    1111

    NV

    任何

    从不执行(不要使用)


    展开全文
  • ARM汇编指令记忆技巧

    2021-02-24 21:39:57
    汇编指令本质是机器指令的助记符,然而在英文环境诞生的汇编助记符给非母语学习者的记忆带来了一些困难。 最好的记忆方式是英文全称理解 + 多编码 研究arm指令发现,arm指令字母编排是有规律可循的,现做记录如下...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 35,336
精华内容 14,134
关键字:

arm汇编指令

友情链接: MATLABupload.zip