amazzzzzing

导航

计算机组成原理 - 指令寻址

计算机组成原理 - 指令寻址

指令寻址和数据寻址

  • 指令寻址是指寻找下一条需要执行的指令地址。指令寻址通过顺序寻址(PC+1)或转移类指令实现。
  • 数据寻址是指在指令中表示一个操作数的地址。数据寻址有多种寻址方式。数据寻址的指令格式如:操作码+地址码(寻址特征+形式地址)

数据寻址方式

  • 隐含寻址。例如单地址指令将累加器(ACC)作为隐含第二操作数。
  • 立即数寻址。指令的形式地址即为操作数。
  • 直接寻址。指令的形式地址为操作数在主存中的地址,也即形式地址就是地址(注意指令的组成是操作码+地址码)。操作数地址=形式地址,即 \(EA=A\)
  • 间接寻址。指令的形式地址为操作数在主存中的地址的地址,也即形式地址是地址的地址。操作数地址=对形式地址进行一次间址,即 \(EA=(A)\)
  • 寄存器寻址。指令的形式地址为存储了操作数地址的寄存器编号,也即形式地址是地址的寄存器编号。操作数地址=形式地址对应寄存器的内容,即 \(EA=R\)
  • 寄存器间接寻址。指令的形式地址为存储了操作数地址的地址的寄存器编号,也即形式地址是地址的地址的寄存器编号。操作数地址=形式地址的地址为对应寄存器的内容,即 \(EA=(R)\)
  • 相对寻址。PC+形式地址形成有效地址。一般用于转移指令。注意CPU取指令时,PC会自动执行+1,因此相对寻址要考虑当前指令的长度。\(EA=PC+A\)
  • 基址寻址。BR+形式地址形成有效地址。基址寄存器面向操作系统。解决程序逻辑地址和物理地址的无关性(映射关系)。\(EA=BR+A\)
  • 变址寻址。IX+形式地址形成有效地址。变址寄存器面向用户。如处理数组问题。\(EA=IX+A\)
  • 堆栈寻址。即操作数含隐含地址SP(堆栈指针)。读写一个堆栈单元后有自动完成的对SP的增减操作。

相对寻址

示例代码:
test.c

int main()
{
  int a = 100;
  int b = 100;

  if (a==100)
    goto tag2;

  a = 10;
tag2:
  b = 10;
}

环境1

x64 - linux - gcc
gcc test.c --> a.out
objdump -d a.out

00000000004004d6 <main>:
  4004d6:	55                   	push   %rbp
  4004d7:	48 89 e5             	mov    %rsp,%rbp
  4004da:	c7 45 f8 64 00 00 00 	movl   $0x64,-0x8(%rbp)
  4004e1:	c7 45 fc 64 00 00 00 	movl   $0x64,-0x4(%rbp)
  4004e8:	83 7d f8 64          	cmpl   $0x64,-0x8(%rbp)
  4004ec:	74 09                	je     4004f7 <main+0x21>
  4004ee:	c7 45 f8 0a 00 00 00 	movl   $0xa,-0x8(%rbp)
  4004f5:	eb 01                	jmp    4004f8 <main+0x22>
  4004f7:	90                   	nop
  4004f8:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)
  4004ff:	b8 00 00 00 00       	mov    $0x0,%eax
  400504:	5d                   	pop    %rbp
  400505:	c3                   	retq   
  400506:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
  40050d:	00 00 00 

je指令所在地址为 4004ec,跳转偏移为9,跳转到 4004f7,实际跳转偏移为 (4004f7-4004ec) = 0xb,也即跳转实际过程是:
执行指令之后,(PC) + 指令长度(2) -> PC,
相对寻址,add = PC + 0x9 = 4004ec + 0x2 + 0x9 = 4004ec + 0xb。

环境2

ARMv7 32bit
gcc test.c --> a.out
objdump -d a.out

000103d0 <main>:
   103d0:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   103d4:	e28db000 	add	fp, sp, #0
   103d8:	e24dd00c 	sub	sp, sp, #12
   103dc:	e3a03064 	mov	r3, #100	; 0x64
   103e0:	e50b3008 	str	r3, [fp, #-8]
   103e4:	e3a03064 	mov	r3, #100	; 0x64
   103e8:	e50b300c 	str	r3, [fp, #-12]
   103ec:	e51b3008 	ldr	r3, [fp, #-8]
   103f0:	e3530064 	cmp	r3, #100	; 0x64
   103f4:	0a000002 	beq	10404 <main+0x34>
   103f8:	e3a0300a 	mov	r3, #10
   103fc:	e50b3008 	str	r3, [fp, #-8]
   10400:	ea000000 	b	10408 <main+0x38>
   10404:	e1a00000 	nop			; (mov r0, r0)
   10408:	e3a0300a 	mov	r3, #10
   1040c:	e50b300c 	str	r3, [fp, #-12]
   10410:	e3a03000 	mov	r3, #0
   10414:	e1a00003 	mov	r0, r3
   10418:	e28bd000 	add	sp, fp, #0
   1041c:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
   10420:	e12fff1e 	bx	lr

beq 指令毫无疑问也是相对地址,如

103f4:	0a000002 	beq	10404 <main+0x34>

0x10404-0x103f4=0x10=16

可猜测公式为

\[目标地址 = \text{PC} + 4*\text{offset} + 8 \]

对于第二个跳转,为

10400:	ea000000 	b	10408 <main+0x38>

符合公式。

对于为何为加上8(而不是PC执行一条指令的偏移值4),这与具体环境有关。armv7为三级流水线(RISC必须有流水线),因此PC指向正在取指的指令,即8。

posted on 2020-10-31 17:34  amazzzzzing  阅读(1525)  评论(0)    收藏  举报