程序计数器是否保存当前地址或下一条指令的地址?

Bis*_*hnu 5 assembly cpu-architecture

作为初学者和自学者,我正在学习集会,目前正在阅读由Allen Hollub撰写的The C Companion一书的第3章.我无法理解他在具有双字节字的假想演示机器中描述的程序计数器或PC的描述.以下是第57页的PC说明.

"PC始终保存当前正在执行的指令的地址.它会在执行每条指令时自动更新,以保存下一条要执行的指令的地址.......这里的重要概念是PC保存下一条指令的地址,而不是指令本身."

我无法理解保持当前地址和下一条指令的地址之间的区别.PC是否同时在两个连续的字节中保存两个地址?

Mar*_*nau 5

我无法理解他在具有两个字节字的虚构演示机中描述的程序计数器或 PC 的描述。

他正在描述一个简单的 CPU,它解释了 CPU 的一般工作方式

真正的 CPU要复杂得多:

在许多手册(对于任何类型的 CPU)中,您会发现这样的句子:“PC 寄存器被压入堆栈。”

这通常意味着从call指令返回后执行的指令的地址被压入堆栈。

然而,这样的句子并不是 100% 正确的:在 68k CPU 的情况下(见下文),写入的是下一条指令的地址,而不是当前指令的指令加 2!

对于大多数 CPU,PC-relativejump指令是相对于下一条指令的地址;但是也有反例(例如 PowerPC VLE)。

32 位 x86 CPU(用于大多数台式机/笔记本电脑)

在这种CPU上,只call 直接读取EIP寄存器,只有跳转指令写入EIP。这已经足够“绝缘”了,这个寄存器是CPU中的一些内部电路,如果根本没有物理EIP寄存器,你不一定知道它的内容。

(你可以指望int像指示int3int 0x80为读CS:EIP为好,因为他们要推一个异常帧,但更有意义,把它们当作触发异常处理机制。

很可能不同的 x86 CPU 内部工作方式不同,因此 EIP“寄存器”的实际内容在不同的 CPU 中是不同的。(而且现代高性能实现不会只有一个 EIP 寄存器,但它们会做任何必要的事情来保留这种错觉并在需要时推送正确的返回地址。)

(相对于 PC 的跳转是相对于下一条指令的地址。)

64 位 x86 CPU

这些 CPU 有直接使用 RIP 寄存器的指令,就像mov eax,[rip+symbol_offset]做一个相对于 PC 的静态数据加载;使共享库和 ASLR 的位置无关代码的效率明显高于 32 位 x86。在这种情况下,“RIP”是下一条指令的地址。

68k

这些 CPU 也有可能直接使用 PC 寄存器的内容。在这种情况下,PC 反映了当前指令的地址加 2(我在这里不确定)。

由于此类指令至少有 4 个字节长,因此 PC 寄存器的值将反映指令“中间”字节的地址。

手臂

在 ARM CPU 上读取 PC 时(可以直接读取!)该值通常反映当前指令的地址加 8,在某些情况下甚至加 12!

(指令长度为 4 个字节,因此“当前指令加 8”表示:前面两条指令的地址!)

  • `mov eax,[rip]` 加载下一条指令的 4 个字节。我认为您的意思是“lea rax, [rip]”,它只是 * 读取 * RIP 而不是取消引用它。32 位 x86 具有 `call`,它将当前 IP/EIP/RIP 作为返回地址推送,并且 [以这种方式记录](http://felixcloutier.com/x86/CALL.html)。所以 x86 确实有 PC=next insn。[直接读取程序计数器](/sf/ask/41997791/)。另请参阅[为什么不能直接设置指令指针?](/sf/answers/2880501921/),了解有关 32 位 ARM 如何将 PC 作为 16 个通用寄存器之一公开的更多信息。 (2认同)