计算机组成原理 - 指令寻址
计算机组成原理 - 指令寻址
指令寻址和数据寻址
- 指令寻址是指寻找下一条需要执行的指令地址。指令寻址通过顺序寻址(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) 收藏 举报