Skip to content

处理器的寻址方式

ShenYj edited this page Apr 18, 2022 · 1 revision

处理器的寻址方式

寻址方式是指通过指令中给出的地址码字段来寻找真实操作数地址的方式,ARM处理器支持九种寻址方式。

分别是立即数寻址寄存器寻址寄存器偏移寻址寄存器间接寻址基址变址寻址多寄存器寻址相对寻址堆栈寻址和块拷贝寻址

  • 立即寻址

    立即寻址是最简单的一种寻址方式,在立即寻址指令中,后面的地址码部分为立即数,多用于给寄存器赋初值。

    立即寻址指令中的操作码字段后面的地址码部分即是操作数本身,也就是说,数据就包含在指令当中,取出指令也就取出了可以立即使用的操作数(这样的数称为立即数)。

    立即数以"#"为前缀,0x开头表示十六进制。

    立即数也有严格要求,并非随便写个数值就是合法的

    • e.g.

      MOV R0,#64        ;  R0  ← 64
      ADD R0, R0, #1    ;  R0   ← R0 + 1
      SUB R0, R0, #0X3D ;  R0   ← R0 – 0X3D
      
  • 寄存器寻址​

    寄存器寻址就是利用寄存器中的数值作为操作数,也称为寄存器直接寻址。

    操作数的值在寄存器中,操作数的值在寄存器中,指令执行时直接从寄存器中取值操作

    • e.g.

      ADD R0,R1, R2         ;R0  ← R1 + R2
      
  • 寄存器移位寻址

    这是ARM指令集特有的寻址方式,它是在寄存器寻址得到操作数后再进行移位操作,得到最终的操作数。

    寄存器移位寻址是ARM指令集特有的寻址方式。当第2个操作数是寄存器移位方式时,第2个寄存器操作数在与第1个操作数结合之前,选择进行移位操作。

    • e.g.

      MOV R0,R2,LSL  #3   ;R0 ← R2 * 8 ,R2的值左移3位,结果赋给R0。
      MOV R0,R2,LSL  R1   ;R2的值左移R1位,结果放入R0。
      
    • 可采用的移位操作如下:

      • LSL:逻辑左移(Logical Shift Left),寄存器中字的低端空出的位补0。
      • LSR:逻辑右移(Logical Shift Right),寄存器中字的高端空出的位补0。
      • ASL:算术左移(Arithmetic Shift Left),和逻辑左移LSL相同。
      • ASR:算术右移(Arithmetic Shift Right),移位过程中符号位不变,即如果源操作数是正数,则字的高端空出的位补0,否则补1。
      • ROR:循环右移(Rotate Right),由字的低端移出的位填入字的高端空出的位。
      • RRX:带扩展的循环右移(Rotate Right eXtended),操作数右移一位,高端空出的位用进位标志C的值来填充,低端移出的位填入进位标志位。
  • 寄存器间接寻址

    寄存器间接寻址就是把寄存器中的值作为地址,再通过这个地址去取得操作数,操作数本身存放在存储器中。

    寄存器间接寻址指令中的地址码给出的是一个通用寄存器的编号,所需的操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针。

    • e.g.

      LDR R0,[R1]     ;R0 ←[R1],以寄存器R1的值作为操作数的地址,把取得操作数传送到R0中
      ADD R0,R1,[R2]  ;R0 ←R1 + [R2],以寄存器R2的值作为操作数的地址,取得操作数后与R1相加,结果存入寄存器R0中。
      
  • 基址寻址(寄存器基址变址寻址)

    寄存器基址变址寻址又称为基址变址寻址,它是在寄存器间接寻址的基础上扩展来的。它将寄存器(该寄存器一般称作基址寄存器)中的值与指令中给出的地址偏移量相加,从而得到一个地址,通过这个地址取得操作数。

    基址寻址就是将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地址。基址寻址用于访问基址附近的存储单元,常用于查表、数组操作、功能部件寄存器访问等。

    • e.g.

      LDR R0,[R1,#4]    ;R0 ←[R1 + 4],将R1的内容加上4形成操作数的地址,取得的操作数存入寄存器R0中。
      LDR R0,[R1,#4]!  ;R0 ←[R1 + 4]、R1 ←R1 + 4,将R1的内容加上4形成操作数的地址,取得的操作数存入寄存器R0中,然后,R1的内容自增4个字节。其中!表示指令执行完毕把最后的数据地址写到R1。
      LDR R0,[R1,R2]    ;R0 ←[R1 + R2],将寄存器R1的内容加上寄存器R2的内容形成操作数的地址,取得的操作数存入寄存器R0中。
      STR R0, [R1,#-4] ;R0→[R1 -4],将R1中的数值减4作为地址,把R0中的数据存放到这个地址中。
      LDR R0,[R1],#4    ;R0 ←[R1]、R1 ←R1+4
      
  • 多寄存器寻址

    多寄存器寻址一次可传送几个寄存器值,允许一条指令传送16个寄存器的任何子集或所有寄存器。

    这种寻址方式可以一次完成多个寄存器值的传送

    • e.g.

      ; LDM:Load Data from Memory to Register.
      ; R1←[R0],R2←[R0+4],R3←[R0+8],R4←[R0+12]
      ; 该指令的后缀IA表示在每次执行完加载/存储操作后,R0按字长度增加,因此,指令可将连续存储单元的值传送到R1~R4。
      LDMIA  R0,{R1,R2,R3,R4}     
      LDMIA  R0,{R1-R4}  ;功能同上。
      

    使用多寄存器寻址指令时,寄存器子集的顺序如果由小到大的顺序排列,可以使用“-”连接,否则,用“,”分隔书写。

  • 相对寻址

    相对寻址是一种特殊的基址寻址,特殊性是它把程序计数器PC中的当前值作为基地址,语句中的地址标号作为偏移量,将两者相加之后得到操作数的地址。

    相对寻址是基址寻址的一种变通。由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址。

    • e.g.

      BL   NEXT  ;相对寻址,跳转到NEXT处执行
      
  • 堆栈寻址

    堆栈是一个按特定顺序进行存取的存储区,操作顺序为“后进先出” 。堆栈寻址是隐含的,它使用一个专门的寄存器(堆栈指针 Stack Pointer, SP) 指向一块存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。

    存储器堆栈可分为两种:
    向上生长:向高地址方向生长,称为递增堆栈
    向下生长:向低地址方向生长,称为递减堆栈

    堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈
    满堆栈在向堆栈存放数据时的操作是先移动SP指针,然后存放数据。在从堆栈取数据时,先取出数据,随后移动SP指针。这样保证了SP一直指向有效的数据。

    堆栈指针指向下一个待压入数据的空位置,称为空堆栈
    空堆栈在向堆栈存放数据时的操作是先放数据,然后移动SP指针。在从堆栈取数据时,是先移动指针,再取数据。这种操作方式保证了堆栈指针一直指向一个空地址(没有有效数据的地址)。

    上述两种堆栈类型的组合,可以得到四种基本的堆栈类型:

    • 满递增:堆栈向上增长,堆栈指针指向内含有效数据项的最高地址。指令如LDMFA、STMFA等;

    • 空递增:堆栈向上增长,堆栈指针指向堆栈上的第一个空位置。指令如LDMEA、STMEA等;

    • 满递减:堆栈向下增长,堆栈指针指向内含有效数据项的最低地址。指令如LDMFD、STMFD等;

    • 空递减:堆栈向下增长,堆栈指针向堆栈下的第一个空位置。指令如LDMED、STMED等。

    • e.g.

      ; STM: Store Data From register to Stack (Memory).
      STMFD  SP!,{R1-R7, LR}   ;将R1-R7, LR压入堆栈。满递减堆栈。
      LDMED  SP!,{R1-R7, LR}   ;将堆栈中的数据取回到R1-R7, LR寄存器。空递减堆栈。
      
  • 块拷贝寻址

    块拷贝寻址用于寄存器数据的批量复制,它实现从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器传送数据。块拷贝寻址与堆栈寻址有所类似。两者的区别在于:堆栈寻址中数据的存取是面向堆栈的,块拷贝寻址中数据的存取是面向寄存器指向的存储单元的。

    在块拷贝寻址方式中,基址寄存器传送一个数据后有4种增长方式

    1. IA:每次传送后地址增加4;(Increment After Operating)
    2. IB:每次传送前的地址增加4;(Increment Before Operating)
    3. DA:每次传送后地址减少4;(Decrement After Operating)
    4. DB:每次传送前地址减少4。(Decrement Before Operating

    对于32位的ARM指令,每次地址的增加和减少的单位都是4 个字节单位

    • e.g.

      STMIA  R0!,{R1—R7};将R1-R7的数据保存到R0指向的存储器中,存储器指针在保存第一个值之后增加4,向上增长。R0作为基址寄存器。
      STMIB  R0!,{R1—R7};将R1-R7的数据保存到存储器中,存储器指针在保存第一个值之前增加4,向上增长。R0作为基址寄存器。
      STMDA  R0!,{R1—R7};将R1-R7的数据保存到R0指向的存储器中,存储器指针在保存第一个值之后减少4,向下减少。R0作为基址寄存器。
      STMDB  R0!,{R1—R7};将R1-R7的数据保存到存储器中,存储器指针在保存第一个值之前减少4,向下减少。R0作为基址寄存器。
      
  • ARM指令中{!},为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
  • 基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。
  • {^}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。

Getting Started

Social

Clone this wiki locally