ARM体系架构—ARMv7-A指令集:内存操作指令

时间:2024-03-16 14:33:24

一、ARMv7-A指令集

ARMv7-A架构是32位处理器架构。也是load/store架构,即数据处理指令操作在通用寄存器完成,只有load/store指令可以访问内存。此外ARM指令集还有一大特点,就是ARM指令集几乎所有的指令都可以增加条件码。
ARM指令集可以归为一下四类:

  1. 数据处理操作(ALU操作例如ADD);
  2. 内存操作(load/store);
  3. 控制流(循环,跳转,条件码等);
  4. 系统(协处理器,debug,模式切换等等)。

本文重点介绍内存操作指令。

一、ARMv7-A内存操作指令

ARM core中的ALU(Arithmetic Logic Unit)只能用于对寄存器的运算处理。只有load和store指令可以执行内存的访问,其中:

  • load指令表示将数据从内存读到寄存器中,memory->register
  • store指令表示将数据从寄存器写的内存,register->memory

常见的load和store指令是LDR(Load Register)和STR(Store Register),和其他指令一样,内存操作指令也可以跟条件码后缀。关于条件码的说明请参看《ARM体系架构—ARMv7-A指令集:数据处理指令》
Load和Store指令可以跟B(Byte,8bit),H(Halfword,16bit),D(Doubleword,64bit)后缀,用于指示内存操作的长度。此外还可以跟S(signed)后缀,用于指示数据是否带符号,之所以存在S(signed)后缀,是因为在数据8bit或16bit读写时可以保留高位的符号位。不加这些后缀,表示内存操作长度是32bit。
ARM体系架构—ARMv7-A指令集:内存操作指令
上图展示了内存操作指令,可以根据访问内存的长度和访问内存权限划分内存操作指令。
对于内存访问长度的说明:

  1. 无长度后缀表示32bit访问;
  2. H后缀,表示16bit访问,用于STR指令;
  3. H后缀,SH后缀,表示无符号/有符号16bit访问,用于LDR指令;
  4. B后缀,表示8bit访问,用于STR指令;
  5. B后缀,SB后缀,表示无符号/有符号8bit访问,用于LDR指令;
  6. D后缀,表示32bit访问,用于LDR/STR指令;
  7. D后缀,表示64bit访问,用于LDREX/STREX指令;

对于内存访问权限的说明:

  1. 无权限后缀表示特权模式访问;
  2. T后缀,表示非特权模式访问(用户模式,PL0),用于LDR/STR;
  3. EX后缀,表示独占模式访问,用于LDR/STR,该指令用于共享内存同步;

按照寻址方式,内存操作指令分为两种:

  1. 单寄存器内存操作指令;
  2. 多寄存器内存操作指令。

二、单寄存器寻址内存操作指令

单寄存器寻址内存操作指令,将地址分为两部分:基址寄存器和偏移量。

  • 基址寄存器可以是R0-R12,SP或者LR。对于load操作,基址寄存器还可以是PC;
  • 偏移量又存在三种形式:立即数,寄存器和移位后的寄存器。

基址寄存器和偏移量配合寻址模式计算的模式,有三种:

  1. 偏移量寻址模式:寄存器基址加上或者减去偏移量,计算出地址;
  2. 前索引寻址模式:寄存器基址加上或者减去偏移量,计算出地址,计算出的新地址回写到寄存器基址;
  3. 后索引寻址模式:寄存器基址即内存访问地址,寄存器基址加上或者减去偏移量,计算出的新地址回写到寄存器基址。

以具体实例说明三种寻址计算模式。
ARM体系架构—ARMv7-A指令集:内存操作指令

  1. 偏移量寻址模式,地址为寄存器R1中的值,偏移量为0;
  2. 偏移量寻址模式,地址为寄存器R1中的值+寄存器R2中的值,偏移量为R2中的值;
  3. 偏移量寻址模式,地址为寄存器R1中的值+寄存器R2中的值左移2位,偏移量为R2中的值左移2位;
  4. 前索引寻址模式,地址为寄存器R1中的值+立即数32,偏移量为32,计算出的新地址回写到R1中;
  5. 后索引寻址模式,地址为寄存器R1中的值,偏移量为32,寄存器R1中的值+立即数32计算出的新地址回写到R1中;

需要说明的是对于寻址计算方式的划分只是为了归纳,可能有不同类型的划分方法。例如可以将示例中的1作为单独的一种(寄存器寻址模式),也可以归纳到偏移为0的偏移量寻址模式。方便理解即可,不必拘泥于形式。

再以LDR指令详细说明内存操作指令的格式。
ARM体系架构—ARMv7-A指令集:内存操作指令

  • type:访问内存的长度,B-无符号8bit,SB-有符号8bit,H-无符号16bit,SH-有符号16bit。对于无符号后缀表示多余位数据用0填充;
  • T:指示内存访问指令是否在用户模式下进程;
  • cond:条件码(CPSR寄存器状态位);
  • Rt:目标寄存器;
  • Rn:基址寄存器;
  • !:最终计算的地址是否写回Rn;
  • offset:立即数偏移;
  • Rm:存储偏移地址的寄存器;
  • shift:用于寄存器或立即数偏移量移位值。

三、多寄存器寻址内存操作指令

load/store指令提供的多寄存器寻址内存操作指令,可以实现超过32bit的内存访问。在栈操作以及内存拷贝的应用中优势明显。
多寄存器寻址指令为LDM(Load Multiple registers)和STM(Store Multiple registers)。

LDM及STM指令格式如下图所示。
ARM体系架构—ARMv7-A指令集:内存操作指令

  • addr_mode:四种地址模式,IA-每次传输后地址增加(默认模式),IB-每次传输前地址增加,DA-每次传输后地址减小,DB-每次传输前地址减小;
  • cond:条件码(CPSR寄存器状态位);
  • Rn:基址寄存器;
  • !:最终计算的地址是否写回Rn;
  • reglist:存储数据的寄存器列表,多个寄存器或寄存器范围使用“,”隔开,寄存器范围用“-”连接;
  • ^:寄存器列表中不包含PC时,该后缀表示load/store寄存器是用户模式的寄存器,而不是当前模式的寄存器;寄存器列表中含有PC时,该后缀表示除了正常传输数据外,将SPSR寄存器拷贝到CPSR中,用于异常返回处理,这种情况只发生在异常模式。

举例说明LDM的使用。
ARM体系架构—ARMv7-A指令集:内存操作指令

  • 将R10所指内存地址的值,传输到R0-R3和R12寄存器中,“,”隔开非连续寄存器R12,“-”连接寄存器范围R0-R3;
  • IA后缀,传输数据后地址增加4字节,共传输5个寄存器,即20字节数据;
  • R10 = R10 + 20,“!”即将最终内存地址回写到寄存器R10中。

IA,IB,DA,DB四种后缀,在用于SP寄存器时,可以使用别名FD(Full Descending), FA(Full Ascending), ED(Empty Descending), EA(Empty Ascending),从栈的角度指定栈满或栈空,以及栈的增长方向。

  • 满堆栈:SP栈顶指针指向最后入栈的数据;
  • 空堆栈:SP栈顶指针指向下一个待入栈的数据的空位置。

寄存器R0-R5入栈及出栈指令:
ARM体系架构—ARMv7-A指令集:内存操作指令
下图以R0,R1寄存器入栈分析其过程:

  • 内存地址向上增长,栈地址向下增长;
  • SP栈顶指针地址减4,R2寄存器入栈;
  • SP栈顶指针地址减4,R1寄存器入栈;
  • 满堆栈递减后缀FD,SP栈顶指针最终指向R1寄存器入栈的位置。
    ARM体系架构—ARMv7-A指令集:内存操作指令

四、SWP,SWPB

除了以上介绍的内存操作指令外,还有SWP(Swap)和SWPB(Swap Byte)指令用于寄存器和内存的值互换。
其指令格式如下:
ARM体系架构—ARMv7-A指令集:内存操作指令

  • cond:条件码(CPSR寄存器状态位);
  • B:单字节交换;
  • Rt:目标寄存器;
  • Rt2:源寄存器,可以和Rt一样;
  • Rn:地址寄存器,不能和Rt,Rt2一样;

SWP将Rn所指内存单元的值读到Rt,同时将Rt2寄存器值写入到该内存单元。当Rt与Rt2一样时,即寄存器与内存数据交换。

SWP/SWPB指令,在某些情况下,体系结构不能保证在加载和存储之间不会对这些内存位置进行内存访问,因而内存不安全,ARMv7提供了LDREX/STREX和LDREXB/STREXB替代SWP/SWPB。因而SWP/SWPB指令是可选指令,可以被处理器被弃用。
ARMv7已经支持虚拟化,无论是否弃用SWP/SWPB指令,在虚拟化Hyp模式下,都没有定义SWP/SWPB指令。