ARM编程基础
本章将简要介绍ARM指令集,移位操作以及主要的寻址方式

更详细的 ARM 指令相关内容,可参考
ARM Compiler Toolchain Assembler Reference
ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition

一、ARM 指令集

ARMv7 架构是一种 32 位处理器架构。它是一种加载/存储架构,这意味着数据处理指令只能对通用寄存器中的值进行操作。只有加载和存储指令才能访问内存。通用寄存器也是 32 位。

ARMv7架构包含两大主要指令集:ARM指令集和Thumb指令集。

  • ARM 指令集:ARM 处理器的原生32位指令集。指令长度固定为32位,以字(4字节)对齐方式存储。所有32位指令均可访问全部ARM核心寄存器(R0-R15)。
  • Thumb 指令集:Thumb指令集最初在ARM7TDMI处理器中添加,仅包含16位指令。包括Cortex-A系列在内的现代处理器支持Thumb-2技术,该技术扩展了Thumb指令集,提供了16位和32位指令的混合使用。

由于Thumb指令大小仅为ARM指令的一半,其程序体积通常比等效的ARM代码小约三分之一。因此,Thumb指令被用于提高代码密度并减少系统内存需求。当处理器直接连接至窄位宽(16位)内存且无缓存时,Thumb代码的性能也可能优于ARM代码——每个时钟周期可获取一条Thumb指令,而每条32位ARM指令需要两个时钟周期进行获取。

执行Thumb指令时,程序计数器(PC)的值为当前指令地址加4。唯一能直接修改PC的16位Thumb指令是某些编码形式的MOV和ADD。写入PC的值会被强制半字对齐,即忽略最低有效位(LSB),将其视为0。

在ARMCC编译器中,选项–thumb或默认的-arm允许选择编译时使用的指令集。程序在运行时可以在这两种指令集之间切换。

二、ARM指令集中的移位操作

移位与循环移位操作类型:

​1. 逻辑左移 (LSL - Logical Shift Left)

  • ​定义:将位串的每一位向左移动指定位数,右侧空位补零,左侧移出的位丢弃。最后一次移出的位可能作为进位输出。
  • 特点:
    • 适用于无符号数乘以2n的运算。
    • 影响标志位:CF(进位标志)、OF(溢出标志)、ZF(零标志)等。

​2. 逻辑右移 (LSR - Logical Shift Right)

  • ​定义:将位串的每一位向右移动指定位数,左侧空位补零,右侧移出的位丢弃。最后一次移出的位可能作为进位输出。
  • ​特点:
    • 适用于无符号数除以2n的运算。
    • 与算术右移的主要区别是填充方式(补0 vs 补符号位)。

​3. 算术右移 (ASR - Arithmetic Shift Right)

  • ​定义:将位串的每一位向右移动指定位数,左侧空位用原符号位(最高位)填充,右侧移出的位丢弃。最后一次移出的位可能作为进位输出。
  • ​特点:
    • 保留符号位,适用于带符号数除以2n的运算。
    • 示例:-6(补码:11111010)算术右移1位后为-3(补码:11111101)。

​4. 循环右移 (ROR - Rotate Right)​

  • 定义:将位串的每一位向右移动指定位数,右侧移出的位从左侧重新填入,形成循环。最后一次移出的位可能作为进位输出。
  • 特点:
    • 循环操作不丢失数据,常用于加密或位重组。
    • 示例:10111110循环右移4位后变为11101011。

​5. 带扩展的循环右移 (RRX - Rotate Right with Extend)

  • 定义:将位串向右移动1位,左侧空位用进位标志(C)的值填充,右侧移出的位作为新的进位输出。
  • ​特点:
    • 结合进位标志实现扩展循环,适用于多精度运算。
    • 示例:ARM指令中的RRX操作会将C标志位插入高位,低位移出到C标志

总结

操作类型 填充方式 应用场景 典型指令(汇编)
逻辑左移 (LSL) 右侧补0 无符号数乘法 SHL, SAL
逻辑右移 (LSR) 左侧补0 无符号数除法 SHR
算术右移 (ASR) 左侧补符号位 带符号数除法 SAR
循环右移 (ROR) 右侧移出位补到左侧 数据加密/循环处理 ROR
带扩展循环右移 (RRX) 左侧补进位标志C 多精度运算 RRX

三、ARM 指令分类及寻址方式

2.1 ARM 指令分类

ARM指令可以分为6类:

  • 跳转指令
  • 数据处理指令
  • 程序状态寄存器处理指令
  • Load/Store指令
  • 协处理器指令
  • 异常中断产生指令

2.2 ARM指令的寻址方式

  1. 立即寻址(立即数寻址)
    指令操作码字段的地址部分是立即数。立即数前面加上“#”。
    指令中的立即数是由一个8bit的常数X循环右移4bit值Y的两倍的数得到:
      immediate = X ROR (2×Y)
    例如:
      MOV R0, #100 或 MOV R0, #0x64 ; 令R0的数值为100

  2. 寄存器寻址(寄存器直接寻址)
    寄存器寻址是指将寄存器中的数值作为操作数。
    例如:
      MOV R0, R1 ; 将R1的数值放到R0中

  3. 寄存器间接寻址
    操作数存放在存储器中,并将所存放的存储单元地址放入某一通用寄存器中。
    例如:
      LDR R0, [R1] ; 将地址为R1的值的内存单元数据读取到R0中

  4. 寄存器移位寻址
    寄存器的值先进行移位操作再进行指令操作。
    例如:
      MOV R0,R1,LSL #3 ; 将R1中的值先左移 3 位,得到的结果赋值给R0

  5. 基址变址寻址
    将寄存器(该寄存器一般称作基址寄存器)中的值与指令中给出的地址偏移量相加,结果得到的新地址,通过这个地址取得操作数。
    支持寄存器偏移:LDR R0, [R1, R2, LSL #2] ;R1+(R2 LSL 2)得到新的内存地址,将新地址的值赋给R0
    前变址:LDR R0, [R1, #4]!(先计算地址后访问,同时更新基址)
    后变址:LDR R0, [R1], #4(先访问后更新基址)

  6. 多寄存器寻址
    使用多寄存器传送指令LDM/STM,在一条指令中传送多个寄存器的值,可以传送1~16个通用寄存器的值。
    寄存器之间的分隔符使用 “-” 或者 “,”。连续的寄存器之间用 “-” 连接;不连续的寄存器中间用 “,” 分隔。

    4种数据块传输模式:

    • IB(Increment Before):地址增加后再完成数据传送,如STMIB、LDMIB;
    • IA(Increment After):完成数据传送后再地址增加,如STMIA 、LDMIA;
    • DB(Decrement Before):地址先减小再完成数据传送,如STMDB、LDMDB;
    • DA(Decrement After):完成数据传送后再地址减小,如STMDA、LDMDA。

    指令语法:
    LDM{cond}<mode> Rn{!}, {reglist}{^} //从Rn加载到寄存器列表
    STM{cond}<mode> Rn{!}, {reglist}{^} //从寄存器列表存储到Rn

    • ​Rn:基址寄存器(不能为R15),存储操作起始地址。
    • ​!:自动更新基址寄存器值(如LDMIA R0!, {R1-R3}操作后R0指向下一个数据块)。
    • ​reglist:寄存器列表(如{R0,R2-R5,LR}),​低编号寄存器对应低内存地址。
    • ​^:特权模式操作后缀,用于恢复用户模式寄存器或操作程序状态寄存器(如中断返回)。
  7. 堆栈寻址
    堆栈是一种数据结构,按先进后出(First In Last Out,FILO)的方式工作,使用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。
    根据SP指针指向的位置,栈可以分为:

  • 满栈(Full Stack):当堆栈指针SP总是指向最后压入堆栈的数据,称为满栈;
  • 空栈(Empty Stack):当堆栈指针SP总是指向下一个将要放入数据的空位置,称为空栈;
    在这里插入图片描述
    根据SP指针移动的方向,栈可以分为:
  • 递增堆栈(ascending stack):堆栈由低地址向高地址生长。
  • 递减堆栈(secending stack):堆栈由高地址向低地址生长。
    在这里插入图片描述
    4种类型的堆栈工作方式:
  • 满递增(Full Ascending,FA)堆栈
  • 满递减(Full Descending,FD)堆栈
  • 空递增(Empty Ascending,EA)堆栈
  • 空递减(Empty Descending,ED)堆栈。
    例如:
      STMFD SP!, {R0-R3} ; 将R0-R3的值入栈,满递减堆栈。
      LDMED SP!, {R0-R3} ;将堆栈中的数据取到R0-R3。空递减堆栈。
  1. PC相对寻址
    以PC寄存器为基址寄存器,以指令中的地址标号为偏移量,两者相加形成操作数的有效地址。
    偏移量指出的是当前指令和地址标号之间的相对位置。
    跳转链接指令(子程序调用指令)的寻址方式即是相对寻址方式。
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐