【ARM汇编学习】ARM概述、ARM和Thumb-2

背景——ARM 处理器发展和分类

Cortex系列

ARM公司在经典处理器ARM11以后的产品改用Cortex命名,并分成A、R和M三类,旨在为各种不同的市场提供服务。Cortex系列属于ARMv7架构,由于应用领域不同,基于v7架构的Cortex处理器系列所采用的技术也不相同,基于v7A的称为Cortex-A系列,基于v7R的称为Cortex-R系列,基于v7M的称为Cortex-M系列。

  • Application Processors(应用处理器):面向移动计算,智能手机,服务器等市场的的高端处理器。这类处理器运行在很高的时钟频率(超过1GHz),支持像Linux,Android,MS Windows和移动操作系统等完整操作系统需要的内存管理单元(MMU)。 如果规划开发的产品需要运行上述其中的一个操作系统,你需要选择ARM 应用处理器.
  • Real-time Processors (实时处理器):面向实时应用的高性能处理器系列,例如硬盘控制器,汽车传动系统和无线通讯的基带控制。多数实时处理器不支持MMU,不过通常具有MPU、Cache和其他针对工业应用设计的存储器功能。实时处理器运行在比较高的时钟频率(例如200MHz 到 >1GHz ),响应延迟非常低。虽然实时处理器不能运行完整版本的Linux和Windows操作系统, 但是支持大量的实时操作系统(RTOS)。
  • Microcontroller Processors(微控制器处理器):微控制器处理器通常设计成面积很小和能效比很高。通常这些处理器的流水线很短,最高时钟频率很低(虽然市场上有此类的处理器可以运行在200Mhz之上)。 并且,新的Cortex-M处理器家族设计的非常容易使用。因此,ARM 微控制器处理器在单片机和深度嵌入式系统市场非常成功和受欢迎。
    Cortex-M 处理器家族更多的集中在低性能端,但是这些处理器相比于许多微控制器使用的传统处理器性能仍然很强大。例如,Cortex-M4 和 Cortex-M7 处理器应用在许多高性能的微控制器产品中,最大的时钟频率可以达到400Mhz。

ARM 之五 发展史及各时期内核(ARM1 ~ ARM11 / Cortex)介绍_ZC·Shou的博客-CSDN博客_arm内核

ARM 寄存器

  • 拥有 37 个寄存器——30 个通用寄存器、6 个状态寄存器和一个程序计数器
    image-20220730102637111

    • 30 个 32 位通用寄存器
      • 任何情况下有15个通用寄存器是可见的 r0~r14
      • 其中 r13 是堆栈指针 sp
      • r14 是链接寄存器 lr
    • 程序计数器 pc
      • r15
      • 若从子例程返回,可使用以下指令将链接寄存器复制到 PC 中:MOV pc, lr
    • 应用程序状态寄存器 APSR
      • 存放算术逻辑单元 ALU 状态标记的副本
      • 用于确定是否执行条件指令
      • 可在所有访问模式下使用 MSR 和 MRS 指令访问这些标记
    • 当前程序状态寄存器 CPSR
      • 存放 APSR 标记
      • 存放当前处理器模式
      • 存放中断禁用标记
      • 所有访问模式下只能访问 APSR 标记
      • 其余位需要在特权模式下使用 MSR 和 MRS 指令访问
    • 保存的程序状态寄存器 SPSR
      • 发生异常时,使用 SPSR 存储 CPSR
      • 每种异常处理模式下可以访问一个 SPSR
      • 用户模式和系统模式不是异常处理模式,没有 SPSR

ARM 指令集概述

  • 所有 arm 指令长度都是 32 位的
  • 指令是按字对齐方式存储的
    • 在ARM状态下,指令地址的最低两个有效位始终为0

ARM指令类型

  • 跳转指令
  • 数据处理指令
  • 加载和存储指令
  • 多寄存器加载和存储指令
  • 状态寄存器访问指令
  • 协处理器指令

汇编语言源文件编排

  • 一般格式:{label} {instruction|directive|pseudo-instruction} {;conmment}
    • 即使没有标签,指令前面也要用空格或制表符留出空白
    • 适当使用空行可以使代码更具有可读性
  • 大小写规则:指令助记符、指令和符号寄存器名称都可以使用大写或小写编写,但不能混用
  • 行长度:
    • 行尾放置\可以将较长的源代码分为多行,反斜杠后不能有包括空格和制表符在内的任何字符
    • 汇编程序会将反斜杠或行尾视为空白
  • 标签:
    • 标签是表示地址的符号,汇编期间会计算他的地址
    • 标签的计算相对于定义标签的节的原点地址
    • 程序相对寻址:引用同一节内的标签时,可以使用pc加或减去偏移量
  • 局部标签:以 0~99 范围内的一个数字开头,可以被定义多次
  • 注释:行中的第一个分号标记主食的开始,行尾是注释结束
  • 常数
    • 数字:十进制、十六进制 (0xxx)、n_xxx (基数_数字)、浮点数
    • 布尔值:{TRUE} 或
    • 字符:单引号括起,如'a',或 '\n' 等(标准的C转义)
    • 字符串:双引号括起,若字符串内有 " 或 $ 作为文本,则必须用一对字符表示(转义)。

ARM 汇编指令相关知识

ALU 状态标记

image-20220730133836777

条件代码后缀

  • 满足ALU状态标记时执行代码
    image-20220730100107578

  • 举例:image-20220730222415262

指令宽度说明

  • .W 后缀:32 位编码
  • .N 后缀:16 位编码(如果无法编码为 16 位则报错)
  • 对于向前引用,不带 .W 的 LDR、ADR 和 B 始终生成 16 位指令,即使这会导致无法访问可利用 32 位指令访问的目标。
  • 对于外部引用,不带 .W 的 LDR 和 B 始终生成 32 位指令。

灵活的第二操作数 Operand2

简单来说,较大(超过256)的数最好放入寄存器再执行算术运算,不要直接作为立即数写入指令=

  • 两种形式

    • #constant

      • ARM指令中,constant 可为将 32 位字中的 8 位值向右循环移偶数位后所生成

        的任一值

      • 在 32 位 Thumb-2 指令中,constant 可为:

        • 将 32 位字中的 8 位值向左移动任意位后所产生的任一常数。

        • 格式为 0x00XY00XY 的任意常数。

        • 格式为 0xXY00XY00 的任意常数。

        • 格式为 0xXYXYXYXY 的任意常数。

      • 将 8 位值右移 2、4 或 6 位后所生成的常数可用于 ARM 数据处理指令,但不能用

        于 Thumb-2 指令中。所有其他 ARM 常数可用于 Thumb-2 指令中。

    • Rm {, shift}

      • shift 可以是五种移位指令

        image-20220730221817638

ARM 汇编指令

ELF 节和 AREA 指令

  • ELF (Executable and Linkable Format) 节:可执行可链接文件格式,是独立、已命名、不可分割的代码或数据序列。

  • AREA 指令:标记一节的开始,命名节并设置其属性

ENTRY

  • 标记第一个要执行的指令
  • 初始化代码和异常处理程序也包含入口点

END

  • 指示汇编程序停止处理此文件
  • 每个汇编源模块必须以仅包括 END 指令的一行结束

内存访问指令

LDR 和 STR(直接偏移量)

  • op{type}{cond} Rt, [Rn {, #offset}] ; immediate offset

    image-20220730222656088

(35条消息) 汇编前变址、后变址、回写_wuqi1003的博客-CSDN博客_前变址和后变址

LDR 和 STR(寄存器偏移)

  • 语法: op{type}{cond} Rt, [Rn, +/-Rm {, shiaft}] ; register offset

    image-20220730222830524

LDR(相对pc)和 LDR 伪指令

  • LDR 相对pc: LDR{type}{cond}{.W} Rt, label

    image-20220730222907592
  • LDR 伪指令: LDR{cond}{.w} Rt,=[expr | label-expr]

    • 加载地址或者是一个 32 位常数值
    image-20220730223055483
  • LDR r, label 和 LDR r, =label的区别:
    LDR r, =label 会把label表示的值加载到寄存器中,而LDR r, label会把label当做地址,把label指向的地址中的值加载到寄存器中。
    譬如 label的值是 0x8000, LDR r, =label会将 0x8000加载到寄存器中,而LDR r, label则会将内存0x8000处的值加载到寄存器中。

ADR(立即数+pc→寄存器)

  • 语法: ADR{cond}{.W} Rd,label

    image-20220730223340421

PUSH 和 POP

  • 语法:

    PUSH{cond} reglist
    POP{cond} reglist
    
  • reglist:

    image-20220730223621751

数据处理指令

ADD/SUB/RSB

  • 语法:

    op{S}{cond} {Rd}, Rn, Operand2
    op{cond} {Rd}, Rn, #imm12 ; Thumb-2 only
    
    image-20220730224150041

AND/ORR/EOR

  • 语法: op{S}{cond} Rd, Rn, Operand2

    image-20220730224319820

CMP

  • 语法: CMP{cond} Rn, Operand2

    image-20220730224505141

MOV

  • 语法

     MOV{S}{cond} Rd, Operand2 
     MOV{cond} Rd, #imm16
    
    image-20220730224721589

ASR/LSL/LSR

算术右移、逻辑左移、逻辑右移

  • 指令:

     op{S}{cond} Rd, Rm, Rs 
     op{S}{cond} Rd, Rm, #sh
    
    image-20220730224940309

SDIV/UDIV

有符号/无符号除法

  • 语法

     SDIV{cond} {Rd}, Rn, Rm 
     UDIV{cond} {Rd}, Rn, Rm
    
    image-20220730225110646

MUL/MLA/MLS

乘法、乘加、乘减

  • 指令:

     MUL{S}{cond} {Rd}, Rn, Rm 
     MLA{S}{cond} Rd, Rn, Rm, Ra 
     MLS{cond} Rd, Rn, Rm, Ra
    
    image-20220730225451158
  • 不能将 r15 用作 Rd、Rn、Rm 或 Ra。

跳转指令

B/BL/BX/BLX

跳转、带链接跳转、跳转并交换指令集、带链接跳转并交换指令集

  • 指令:

     op{cond}{.W} label 
     op{cond} Rm
    
    image-20220730225832175
  • 关于状态切换:

    • BX Rm 和 BLX Rm 可从 Rm 的位 [0] 推算出目标状态:
      • 如果 Rm 的位 [0] 为 0,则处理器的状态将改为(或保持在)ARM 状态
      • 如果 Rm 的位 [0] 为 1,则处理器的状态将更改(或保持在)为 Thumb 状 态。
  • 关于 BNE 等:BEQ、BNE、BGT 等都是由 B+cond 组合出来的

CBZ/CBNZ

比较,为零/非零则跳转

  • 语法:

     CBZ Rn, label 
     CBNZ Rn, label
    
    image-20220730230341253
  • 跳转目标必须在指令之后的 4 到 130 个字节之内。

其他指令

NOP

  • 指令:NOP{cond}

伪指令

MOV32

可将一个 32 位常数值或任何地址加载到寄存器

  • 指令: MOV32{cond} Rd, expr

    image-20220730231007458

LDR 伪指令

可将一个 32 位常数值或任何地址加载到寄存器

  • 指令: LDR{cond}{.w} Rt,=[expr | label-expr]

    image-20220730231146554

参考资料

  1. RealView® 编译工具 3.1版 汇编程序指南
  2. ARM ASSEMBLY LANGUAGE Fundamentals and Techniques (SECOND EDITION)
posted @ 2022-07-31 21:35  wheater  阅读(832)  评论(0编辑  收藏  举报