页内地址重定向

Posted by AchanYao on May 20, 2020

背景

程序装载到内存才可以运行。通常,程序以可执行文件格式保存在磁盘上

每个进程有自己的地址空间

  • 一个进程执行时不能访问另一个进程的地址空间
  • 进程不能执行不适合的操作

地址重定位

逻辑地址(相对地址,虚拟地址)

  • 用户程序经过编译、汇编后形成目标代码,目标代码通常采用相对地址的形式,其首地址为0,其余地址都相对于首地址而编址
  • 不能用逻辑地址在内存中读取信息

物理地址(绝对地址,实地址) 内存中存储单元的地址 可直接寻址

为了保证CPU执行指令时可正确访问内存单元,需要将用户程序中的逻辑地址转换为运行时可由机器直接寻址的物理地址,这一过程称为地址重定位

重定位分类

  1. 静态重定位:当用户程序加载到内存时,一次性实现逻辑地址到物理地址的转换。一般可以由软件完成

  2. 动态重定位:在进程执行过程中进行地址变换 → → 即逐条指令执行时完成地址转换。

常用动态重定位方案有页式地址重定位、段式地址重定位、段页式地址重定位

页式地址重定位

设计思想

  • 用户进程地址空间被划分为大小相等的部分,称为页(page)或页面,从0开始编号
  • 内存空间按同样大小划分为大小相等的区域,称为页框(page frame),从0开始编号;也称为物理页面,页帧,内存块
  • 内存分配(规则):以页为单位进行分配,并按进程需要的页数来分配;逻辑上相邻的页,物理上不一定相邻
  • 典型页面尺寸:4K 或 4M

也是存储管理中逻辑地址包含两部分:页号和页内地址

页式地址重定向逻辑实现

Java实现

AbstractAddress.java

package com.achan.addressrelocation.bean;

import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 地址表示
 *
 * @author Achan
 * @date 2020/5/17
 */
@Data
@Accessors(chain = true)
public abstract class AbstractAddress {
    /**
     * 所指向的节点
     */
    protected AbstractAddress address;
    /**
     * 索引,页码,段号,块号
     */
    protected Integer index;
}

AddressTranslator.java

package com.achan.addressrelocation.translator;

import com.achan.addressrelocation.bean.BlockAddress;
import com.achan.addressrelocation.exception.OutOfBoundsException;

/**
 * 地址转换器,适配页式地址重定位、段式地址重定位(如果还写的话)
 *
 * @author Achan
 * @date 2020/5/16
 */
@FunctionalInterface
public interface AddressTranslator {

    /**
     * 逻辑地址转换为物理地址
     *
     * @param logicAddress 逻辑地址
     * @return 物理地址
     * @throws OutOfBoundsException 转换出错时抛出越界异常
     */
    BlockAddress logicAddressToPhysicalAddress(BlockAddress logicAddress) throws OutOfBoundsException;
}

BlockAddress.java

package com.achan.addressrelocation.bean;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * @author Achan
 * @date 2020/5/17
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class BlockAddress extends AbstractAddress {

    /**
     * 块地址最大值
     */
    public static Integer BLOCK_SIZE = 1000;
    /**
     * 地址
     */
    private Integer addressValue;

    public BlockAddress(int addressValue) {
        setAddressValue(addressValue);
    }
}

OutOfBoundsException.java

package com.achan.addressrelocation.exception;

import com.achan.addressrelocation.bean.AbstractAddress;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * 越界中断异常
 * @author Achan
 * @date 2020/5/17
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class OutOfBoundsException extends RuntimeException {

    private AbstractAddress logicAddress;

    public OutOfBoundsException(AbstractAddress logicAddress) {
        super("越界异常");
        this.logicAddress = logicAddress;
    }
}

PageTable.java

package com.achan.addressrelocation.page;

import com.achan.addressrelocation.bean.AbstractAddress;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 页表
 * @author Achan
 * @date 2020/5/17
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class PageTable extends AbstractAddress {

    /**
     * 页表内不一定存储的是块地址,也有可能是下一级页表的地址
     */
    protected List<AbstractAddress> nodes;
    protected Integer size;

    /**
     * 构造页表
     * @param size 页面节点大小,页表项长度
     * @param address 所指向的地址,下级页表
     * @param addresses 页表的值
     */
    public PageTable(int size, AbstractAddress address, AbstractAddress... addresses) {
        this.size = size;
        this.address = address;
        this.nodes = new ArrayList<>(addresses.length);
        nodes.addAll(Arrays.asList(addresses));
    }

    /**
     * 页表长度
     * @return 页表长度
     */
    public int length() {
        return nodes.size();
    }

    /**
     * 对应页号的地址
     * @param index 页号
     * @return 地址
     */
    public AbstractAddress getValue(int index) {
        return nodes.get(index);
    }
}

PageAddressTranslator.java

package com.achan.addressrelocation.page;

import com.achan.addressrelocation.bean.BlockAddress;
import com.achan.addressrelocation.exception.OutOfBoundsException;
import com.achan.addressrelocation.translator.AddressTranslator;
import lombok.Data;

/**
 * @author Achan
 * @date 2020/5/19
 */
@Data
public class PageAddressTranslator implements AddressTranslator {

    private PageTable pageTable;

    /**
     * 构造地址转换器
     *
     * @param pageTable 页表
     */
    public PageAddressTranslator(PageTable pageTable) {
        this.pageTable = pageTable;
    }

    @Override
    public BlockAddress logicAddressToPhysicalAddress(BlockAddress logicAddress) throws OutOfBoundsException {
        PageTable pageTable = this.pageTable;
        // 下标,页号
        int pageNum;
        while (true) {
            pageNum = logicAddress.getAddressValue() / pageTable.getSize();
            if (pageTable.length() < pageNum) {
                throw new OutOfBoundsException(logicAddress);
            }
            if (pageTable.getValue(pageNum) instanceof BlockAddress) {
                break;
            } else {
                // 多级页表
                pageTable = (PageTable) pageTable.getValue(pageNum);
            }
        }
        // 页面偏移量
        int w = logicAddress.getAddressValue() - pageNum * pageTable.getSize();
        return new BlockAddress(((BlockAddress) pageTable.getValue(pageNum)).getAddressValue() * pageTable.getSize() + w);
    }
}