Intel 8086汇编中CS和IP寄存器的作用是什么?

35

所以,正如问题所述,intel的8086中CS和IP寄存器的目的是什么?

我找到了这个解释:

代码段(CS)是一个16位寄存器,包含有处理器指令的64KB段的地址。处理器使用CS段访问所有由指令指针(IP)寄存器引用的指令。不能直接更改CS寄存器。在进行far jump、far call和far return指令时,CS寄存器会自动更新。

对于IP,它的解释如下:

指令指针(IP)是一个16位寄存器。

我不太理解这基本上意味着什么,如果有人能提供更“生动”的解释,那就太好了 :)

6个回答

39

物理地址由两个部分计算得出。 i)段地址。 ii)偏移地址。 CS(代码段寄存器)用于寻址内存中的代码段,即存储代码的内存位置。IP(指令指针)包含在内存中代码段的偏移量。因此,CS:IP用于指向代码在内存中的位置(即计算物理地址)。


28

由于指令指针(IP)为16位,这意味着您只能有64k条指令(2^16),即使在80年代也不多。因此,为了扩展地址空间,你需要第二个寄存器来寻址64k块。你可以将 cs:ip 视为一个32位寄存器,能够寻址2^32字节...即4G,这是使用32位地址的处理器所提供的。 8086使用20位地址,因此可以访问1M内存。


CS 用在哪里? 我读了一些关于段和偏移量的内容,可以说我对段/偏移机制有所理解。 - idjuradj
我扩展了我的问题:那么CS寄存器在哪里使用呢? 我稍微读了一些有关段和偏移量的内容,可以说我对段/偏移机制有所了解。但是,Code Segment寄存器在哪里使用呢?据我所知,有数据段、堆栈段、额外段和提到的代码段?而且由于CS与IP寄存器“配对”,并使用其4位作为偏移量,其他寄存器是否也与IP寄存器配对,或者这4个段寄存器中的每一个都有自己的偏移寄存器? - idjuradj
每次处理器从IP获取新指令时,都会隐式地使用CS。CS指向程序的代码段,并且下一条指令所在的物理地址是透明地组装的。同样地,每当您访问存储在DS中的数据(mov ax,[1234] - 1234隐含地带有DS前缀)时,都会发生类似的情况。您不能对CS做太多事情,但是当您执行长跳转时会使用它。 - user1666959
10
“CS:IP together as one 32 bit register which is then capable of addressing 2^32 bytes” 是错误的。即使在32位处理器的实模式下,CS:IP组合起来也只能使用20位寻址。(严格来说,在286或386+处理器上,如果0xFFFF:0xFFFF=(0xFFFF<<4)+0xFFFF=10FFEF,则CS:IP可以寻址0到0x10FFEF。为了寻址4GB的内存,在386处理器上扩展了IP寄存器成为32位的EIP,可以寻址4GB。) - Michael Petch
同意Michael Petch的评论。基于他们的定义,16位CS:IP最多可以寻址到0x10FFEF。CS的起始地址是固定的,即其值乘以0x10。 - robbie fan

20

接下来要执行的指令是存储在内存地址等于:

16 * CS + IP

尽管寄存器只有16位宽度,但是这允许寻址20位内存(同时也创造了两种编码大多数地址的不同方式)。

CS 的效果类似于其他段寄存器的效果。例如,DS 通过 16*DS 增加数据访问(如果没有指定另一个段寄存器)。

CS

修改 CS 的指令包括:

  • ljmp(远跳转)
  • lcall(远调用),它将 ip 和 cs 推送到堆栈中,然后进行远跳转
  • lref(远返回),它颠倒了远程调用
  • int,它从中断向量表中读取 IP / CS
  • iret,它颠倒了 int 操作

不能像其他段寄存器一样使用 mov 来修改 CS。尝试使用 GNU GAS 2.24 的标准标识符对 CS 进行编码,如果您编写以下内容,则编译器不会报错:

mov %ax, %cs

执行时会导致无效代码异常。

为了观察CS的影响,请按照这里https://dev59.com/HWEh5IYBdhLWcg3wwly8#32483545所述,在引导扇区中添加以下内容并在QEMU中运行。

/* $1 is the new CS, $1f the new IP. */
ljmp $1, $after1
after1:
/* Skip 16 bytes to make up for the CS == 1. */
.skip 0x10
mov %cs, %ax
/* cs == 1 */

ljmp $2, $after2
after2:
.skip 0x20
mov %cs, %ax
/* cs == 2 */

IP(指令指针)

每当执行一条指令时,IP会自动增加该指令的编码长度:这就是程序向前移动的原因!

IP由相同的修改CS的指令修改,以及那些指令的非far版本(更常见的情况)。

无法直接观察IP,因此更难操作它。有关替代方案,请查看以下问题: 直接读取程序计数器


在您提供的示例中,$1和$2可以是任意(有效)值吗?由于$after1和$after2是相对于当前IP的值,所以为了使跳转正确跳转,$1和$2必须为0(如果段寄存器不为0,则16*CS+IP将无法匹配标签,因为$after已经考虑了差异)。 - tartaruga_casco_mole
@tartaruga_casco_mole(好昵称),我认为$after不是相对的,而是绝对的,例如来自https://c9x.me/x86/html/file_module_x86_id_147.html的`EA cd`编码,GNU Gas根据要使用的确切指令编码正确地确定了重定位类型。 我建议从反汇编中确认这一点。 - Ciro Santilli OurBigBook.com

4

由于8086处理器使用20位寻址,我们可以访问1MB的内存,但是8086的寄存器只有16位,因此为了从内存中访问数据,我们需要将代码段寄存器和指令指针寄存器中的值相结合生成物理地址。这是通过将CS的值向左移动4位,然后与IP的值相加来完成的。

示例:

CS的值为1234Hex(十六进制)

IP的值为5678Hex

现在将CS的值左移4位后,其值为12340Hex,然后再与IP的值相加得到179B8Hex,这就是物理地址。


1
一旦在汇编程序文本中编写了 .code,则该 .code 将指向 cs 值。文件中稍早或稍晚的任何命令都将根据 cs:ip 进行寻址,其中 ip 是相对于 cs 的偏移量值。
当然,您必须记住,汇编编译器首先将文本转换为机器码指令。

0

IP寄存器 - IP代表指令指针。它的功能与其他微处理器中的PC(程序计数器)相同,即指向下一个指令,以便BIU单元获取并提供给EU单元。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接