摘要:在pmtest6.asm中,我们已经初步接触了分页机制,但是很显然,上述分页机制浪费比较严重,而且没有体现应有的用处。本节,我们主要介绍如何根据内存容量,恰当地分配页表。
一、理论基础
1.如何获取内存分布信息?
获取内存,需要用到dos下的int 15h中断,可以参考这里:
http://blog.youkuaiyun.com/trochiluses/article/details/20078161
二、代码剖析
在pmtest7中,我们需要对代码结构作出一定的调整:
1、定义库文件:
在库文件lib.c中,定义如下函数:DispAL,DispReturn、DispInt、DispStr
我们仍然采用分段的方式来分析比较陌生的代码:
另外,我们定义了szPMMessage,接着,有这样一句汇编:
push szPMMessage
这句对堆栈的改变是多少?
你要知道,这是push in stack的是地址,而不是具体的字符串。
2.DispInt和DispStr的原理有很大的不同:
1)Dispint中,堆栈中存放的直接是要显示的整数,但是,有几点需要注意
mov eax,[esp+4]中,采用的是ss寻址,而不是ds寻址;为什么esp需要+4,是因为经过call指令之后,堆栈顶部存放的不再是刚刚入栈的整数,而是EIP!!!
2)DispStr中,堆栈中存放的是字符串的地址,同样ebp也是相对ss进行寻址的
3)关于内存寻址符号[]?
[esi]\[gs:edi]\[esp]
注意,内存寻址实际上采用的基地址+变址寻址。语法和对应的实际地址如下
[esi]---> ds:esi
[idata]----->ds:idata
[esp]-------->ss:esp
[ax]------>error!!
stosb------>es:edi
lodsb------->ds:esi
当然,也可以直接指定段寄存器[gs:edi]
3.读取内存信息,确定内存上限的原理是什么?
注意:进行内存信息读取之前,我们需要明白,BIOS读取的内存地址都是64b的,所以,我们只使用低32位就可以了。另外,我们读取到的内存信息,并不是按照基地址从小到大排列的,所以我们要用
if(BaseAddrLow + LengthLow > MemSize)
MemSize = BaseAddrLow + LengthLow;
这一句来检测内存上限(注意,这是内存地址的上限,而不是内存大小的上限)
4.理清代码跳转结构
s16code:init segment info,get meminfo, jmp to protect model:s code32
scode32:display szpmmessage,display title,display memsize, setuppageing,jmp code16 normal