寄存器操作数:(存放在CPU中)
MOV AX,0FFFFH
AX 即为寄存器操作数。
操作数本身存放于寄存器中,在指令中只是给出了几个位的代码来表示它具体存放在那个寄存器中。
内存中的数据经过寄存器读入CPU,进入数据的运算。
内存操作数:(存放在内存中)
其存储于某内存区域,因此叫内存操作数。
- mydata dw 1234H 或 mydata db 12H等
上述中mydata这样的变量
- xx db 0FFH,0
mov bx, OFFSET xx //用offset运算符计算出xx单元的偏移值
mov ax,[bx]
上述中[bx]就叫做非变量名直接寻址的内存操作数
段寄存器:
段寄存器是因为对内存的分段管理而设置的。
为什么需要内存分段?
8086CPU有20根地址线,最大可寻址内存空间为1MB。而8086的寄存器只有16位,指令指针(IP)和变址寄存器(SI、DI)也是16位的。用16位的地址寻址1MB空间是不可能的。所以就要把内存分段,也就是把1MB空间分为24,即16个段,每段不超过64KB(216,16位数据线就可以寻址)。
因此在8086中设置4个16位的段寄存器,用于管理4种段:CS是代码段,DS是数据段,SS是堆栈段,ES是附加段。 把内存分段后,每一个段就有一个段基址,段寄存器保存的就是这个段基址的高16位,称高16位为段基值 ,这个16位的地址左移四位(后面加上4个0)就可构成20位的段基址。
但在描述内存分段时,需要有如下段的信息:1.段的大小;2.段的起始地址;3.段的管理属性(禁止写入/禁止执行/系统专用等)。需要用8个字节(64位)存储这些信息,但段寄存器只有16位。
因此段寄存器中只能存储段号,也叫做段选择符,再由段号映射到存在内存中的GDT(全局段号记录表),读取段的信息。
虚拟空间(虚拟存储器地址空间)/编程空间 (程序的编写空间)
存储管理部件把主存(物理存储器)和辅存(磁盘)看作是一个整体,即虚拟存储器。486允许虚拟存储器容量最大为246=64T,即程序员可在此地址范围内编程,程序可大大超过物理空间。
因此CPU必须将一个虚拟内存空间中的地址转换为物理地址(程序的运行空间)
需要进行两步:
1.首先将给定一个逻辑地址,CPU先利用其段式内存管理单元,先将为个逻辑地址转换成一个线性地址
2.再利用其页式内存管理单元,转换为最终物理地址。
注:
- 如果不分页的话,线性地址就是物理地址;
- 如果分页的话,则由分页部件把线性地址转换为
物理地址。
- 实模式:存储空间仅分段,而不分页;
保护模式:存储空间先分段,再分页。
什么是逻辑地址?
逻辑地址是CPU所生成的地址 ,指的是机器语言指令中,用来指定一个操作数或者是一条指令的地址。
一个逻辑地址由两部份组成,段标识符: 段内偏移量(offset)。段标识符是由一个16位长的字段组成,称为段选择符。段选择符存放在段寄存器中。其中前13位是一个索引号。后面3位包含一些硬件细节。
索引号,或者直接理解成数组下标,它又是什么东东的索引呢?这个东东就是“段描述符(segment descriptor)”,(有数据段描述符,代码段描述符,系统段描述符)。段描述符具体地址描述了一个段。
这样,很多个段描述符,就组了一个数组,叫“段描述符表”,这样,可以通过段标识符的前13位,直接在段描述符表中找到一个具体的段描述符,这个描述符就描述了一个段,每一个段描述符由8个字节组成。段描述符中有Base字段,它描述了一个段的开始位置的线性地址。把Base + offset,就是要转换的线性地址了。
注:
一些全局的段描述符,就放在“全局段描述符表(GDT)”中。
一些局部的,例如每个进程自己的,就放在的“局部段描述符表(LDT)”中。
段选择符中的T1字段,=0,表示用GDT,=1表示用LDT。
如指令:
1.直接寻址
格式:段寄存器:[偏移地址]
mov bx, ds:[1234H] //表示从ds数据段偏移地址为1234H的单元取数——>bx
假设(DS)=5000H 可计算出
线性地址为16d×(DS)+1234H=16d×5000H+1234h=50000H+1234H=51234H 。
命令的最后结果就是把线性地址为51234H的存储单元中的操作数据放入BX中
2.间接寻址
格式:段寄存器:[间址寄存器] / [间址寄存器]
注意:可省略段寄存器是因为会到默认约定的段寄存器中取内容数据
例:
mov ds,数据段段基址
mov bx,buf单元的偏移地址
mov al,ds:[bx]
等价于:mov al,[bx]
间接寄存器和约定访问的逻辑段如下图所示:
分页内存管理
核心:将虚拟内存空间和物理内存空间借划分为大小相同的页,并以页作为内存空间划分的最小单位。空间增长也容易实现:只需要分配额外的虚拟页面,并找到一个闲置的物理页面存放即
为什么需要分页内存管理?
因为有以下优点:
- 不会产生外部碎片化(空间碎片化的根源就是每个程序的大小不一样,这样在空间分配时不存在一致性。解决的办法自然是将空间按照某种规定的大小进行分配。将虚拟内存和物理内存都分成大小一样的部分,我们称之为“页”。),一个进程占用的内存空间可以不是连续的,
- 一个进程的虚拟页面在不需要时,可以存放在磁盘上,不需要全部同时加载到内存上。
- 可以共享小的地址,即页面共享。只要给相应的页表里面做一个相应的记录便可。
在分页系统的机制下:
一个程序发出的虚拟地址由两部分组成:页面号 和 页内偏移值
这个total_page数组有2^20个成员,每个成员是一个地址(32位机,一个地址也就是4字节),那么要单单要表示这么一个数组,就要占去4MB的内存空间。为了节省空间,引入了一个二级管理模式的机器来组织分页单元。
所以每一个32位的线性地址被划分为三部份,页目录索引(10位):页表索引(10位):偏移(12位)
依据以下步骤进行转换:
- cr3寄存器中取出进程的页目录地址(操作系统负责在调度进程的时候,把这个地址装入对应寄存器);
- 根据线性地址前十位,在数组中,找到对应的索引项,因为引入了二级管理模式,页目录中的项,不再是页的地址,而是一个页表的地址。(又引入了一个数组),页的地址被放到页表中去了。
- 根据线性地址的中间十位,在页表(也是数组)中找到页的起始地址;
- 将页的起始地址与线性地址中最后12位相加,得到最终我们想要的物理地址;
原文地址:https://www.cnblogs.com/Hhhighway/p/12684920.html