地址空间是一个进程可用于寻址内存的一套地址集合。每个进程都有一个自己的地址空间,并且这个地址空间独立于其他进程的地址空间(除了在一些特殊情况下进程需要共享它们的地址空间外)。
给每个程序一个自己的地址空间,使得一个程序中的地址28所对应的物理地址与另一个程序中的地址28所对应的物理地址不同。方法:
基址寄存器与界限寄存器
使用一种简单的动态重定位,把每个进程的地址空间映射到物理内存的不同部分。当使用基址寄存器和界限寄存器时,程序装载到内存中连续的空闲位置且装载期间无须重定位,如图3-2c所示。当一个进程运行时,程序的起始物理地址装载到基址寄存器中,程序的长度装载到界限寄存器中。在图3-2c中,当第一个程序运行时,装载到这些硬件寄存器中的基址和界限值分别是0和16 384。当第二个程序运行时,这些值分别是16 384和16384。如果第三个16KB的程序被直接装载在第二个程序的地址之上并且运行,这时基址寄存器和界限寄存器里的值会是32 768和16 384。
每次一个进程访问内存,取一条指令,读或写一个数据字,CPU硬件会在把地址发送到内存总线前,自动把基址值加到进程发出的地址值上。同时,它检查程序提供的地址是否等于或大于界限寄存器里的值。如果访问的地址超过了界限,会产生错误并中止访问。这样,对图3-2c中第二个程序的第一条指令,程序执行
- JMP 28
指令,但是硬件把这条指令解释成为(28+16384=16412)
- JMP 16412
所以程序如我们所愿地跳转到了CMP指令。在图3-2c中第二个程序的执行过程中,基址寄存器和界限寄存器的设置如图3-3所示。
图3-2 重定位问题的说明:a) 一个16KB程序;b) 另一个16KB程序;c) 两个程序连续地装载到内存中
使用基址寄存器和界限寄存器是给每个进程提供私有地址空间的非常容易的方法,因为每个内存地址在送到内存之前,都会自动先加上基址寄存器的内容。在很多实际系统中,对基址寄存器和界限寄存器会以一定的方式加以保护,使得只有操作系统可以修改它们。
使用基址寄存器和界限寄存器重定位的缺点是,每次访问内存都需要进行加法和比较运算。比较可以做得很快,但是加法由于进位传递时间的问题,在没有使用特殊电路的情况下会显得很慢。
程序执行时,必须将地址空间变为绝对地址才能访问系统分配的内存
地址重定位:操作系统把用户程序指令中的相对地址变换成为所在存储中的绝对地址的过程
地址重定位实现了:从逻辑地址到物理地址的转换
地址的静态重定位
定义:在程序运行之前,为用户程序实行了地址重定位工作
一般由操作系统中的重定位装入程序完成
重定位装入程序的输入:用户把自己的作业链接装配成一个相对于 0 编址的目标程序
实现过程:
静态重定位的处理方法为在加载程序到内存中时,将程序中所有的地址都加上在内存中的起始地址。比如一个程序被加载到从1000号开始的内存空间,而且程序中有一条指令JMP 28,那么程序被加载入内存后这条指令会变成 JMP 1028。静态重定位的难点在于区分程序中哪些值是常量,哪些值是地址。
特点:
- 在装入前实现调整
- 地址要有标识
- 每次装入都要进行定位
- 装入后地址不再改变(静态)
地址的动态重定位
定义:在程序执行寻址时进行重定位,访问地址时,通过地址变换机构改变为内存地址,用户程序原封不动的装入内存,运行时再完成地址的定位工作。动态重定位需要硬件的支持,要求系统中配备定位寄存器和加法器。
实现过程:
使用动态重定位的cpu有两个特殊的寄存器:基址寄存器和界限寄存器。当一个进程运行时,程序的起始地址被装载到基址寄存器中,程序的长度被装载到界限寄存器中。当程序要进行内存操作时,cpu会首先将指令中的地址加上基址寄存器中的地址,再把地址送到内存总线。此外,cpu还会检查地址是否大于界限寄存器中的值。如果访问的地址超出了界限则会出错并停止访问。
特点:
- 程序可装入任意内存区域(不要求占用连续的内存区)
- 只装入部分程序代码即可运行
- 改变系统时不需要改变程序(程序占用的内存空间动态可变,只需要改变定位寄存器中的值即可)
- 程序可方便共享