操作系统原理(基于Win32汇编和MFC Windows)

本文深入探讨了计算机系统中操作系统的基本原理,包括硬件管理、指令系统、虚拟存储器的不同形式及其在现代操作系统中的应用,特别是Windows操作系统中的消息驱动机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在研究操作系统原理的时候让我们先来了解一下电脑组成 电脑是有硬件和软件一起构成,而专业人士往往把没用装任何软件系统的计算机叫裸机 计算机通过软件系统来更好的管理硬件 而计算机系统即我们所认为的操作系统其实是研究软件如何来管理硬件 一般分为文件管理 设备管理 进程管理 存储管理 和作业管理五个部分 不过有的专家把作业管理和进程管理统称为处理机调度 所以我们常认为 系统分为四个部分的管理
在操作系统中我们研究的比较多的是中断,与指令系统.因为他们维持计算机正常运行.特别是在系统结构中,指令属于计算机硬件底层,因此他一般暂存在寄存器中,由于流水线的作用,他被"一次重叠"的执行,所谓的"一次重叠"是同时解释相邻两条指令,但是又由于最大吞吐率的瓶颈,导致指令的效率减低,一次又提出,瓶颈段再细分的方式,或是通过瓶颈段并行流动.指令被来回的从一个寄存器存入另一个寄存器,特别在这里提到通用寄存器,在我学汇编的时候,就把16位系统的通用寄存器分为高八位和低八位,但统称为ax,bx,cx,dx四个大的通用寄存器,还有四个段寄存器,两个标志寄存器,在32为系统没有太大改变,只是字长发生改变,通用寄存器的名字前加了E,eax,ebx,ecx,edx四个16位通用寄存器,功能是不变,这些寄存器只是实现功能算法,还有些寄存器,实现暂存数据和保存站.还有很多BUS,因为在计算机中只有数据总线和控制总线两种.数据总线(DB,DataBus)主要负责传送数据,控制总线(CB,ControlBus)主要负责传送控制信号和时序信号.
不过拿那些存储系统来讲,那就不值一提了!
我自认为那些构建页的映像机构相当复杂.
      首先就是虚拟存储器就有三种方式,进行页的转换,由虚页号转换为实页号.
      段式虚拟存储器,页式虚拟存储器,段页式虚拟存储器.每一种都有他的特征.
段式存储方式把虚拟存储器分为段.分段式的好处,我认为他构建了另一种适合于程序执行的方式.这是我自己认为的.
      因为我在编程的时候,将每个程序模块,装入段中,因此我调用某段时,只要访问该段.比如说我访问Call (2,100)打比方是汇编语言中访问方式,我拓宽了访问的尺度,2是段号,而100是偏移后的段,因为段较小.它能程序片段,比如说C语言中的Main函数可以单独取段放置.因此我根据段号找到基址地址+偏移的段,比如说2对应基址地址是400,那么该段对应的实地址(物理地址)是400+100=500.
     可惜的是他虽具有良好的编程效果,在编程地址中显得非常灵活,有点像寻址的方式.但是他调入内存的大小比内存本身还小,这不是设计者的初衷哦!
     可笑的是页是存储方式与段式存储方式走向两个极端,页创建了页表法,在主存中保存了页表.每个页的大小过于大.而导致执行效率的下降,虽满足了设计者的初衷,但是牺牲了效率是不划算的.而实地址页的计算方式是,页号*1024+页内位移.
因此设计者提出了一种适中的方法,段页式存储,基于页式和段式的存储适中的方式.这方式确实想设计者想象的那样,他构建了另一种映像机制,创建了二维的页表.通过段和页来定位.
        但在这里我还得谈及所谓的段在编程起到不可磨灭的作用.因为我在学习汇编语言时,我们把程序的整个部分分为二个段,数据段和代码段.当然这只是整体的,数据段里面还分为各种各样的数据段,比如常数段,初始段等等.代码段可能是由多个程序模块组成.但是我前面不是讲过吗?为什么存储器要把空间分为段,就是不同的段都有他的地址, 而在寻址的时候却很方便,想想我以前的一篇关于介绍数组是如何存储在主存中的,他依靠主存地址和偏移地址的和和起始地址之间范围的连续空间来存储数组.这是个数据段,但确切的说这有点像浮动空间,指的是一个范围.这个段可能在代码段中有所修改,他的地址是可变的.
哎!说了这么多来看看Window操作系统吧!
这是个典型实例,汇编也最能体现段在操作系统原理中的重要位置.
Windows操作系统是典型的段操作系统,他的所用控件操作依靠消息驱动来维持.
看如下的汇编基于Win32的开发的窗体.

.386
.model flat,stdcall
option casemap:none
;工作模式
include /masm32/include/windows.inc
include /masm32/include/gdi32.inc
include /masm32/include/user32.inc
include /masm32/include/kernel32.inc
includelib /masm32/lib/gdi32.lib
includelib /masm32/lib/user32.lib
includelib /masm32/lib/kernel32.lib

.data?
hInstance dd ?
hWinMain dd ?
.const
szClassName db 'MyClass',0
szCaptionMain db 'My frist Window !',0
szText db 'Win32 Assembly,Simple and powerful !',0
.code
;窗口过程
_ProcWinMain proc uses ebx edi,hWnd,uMsg,wParam,lParam
local @stPs:PAINTSTRUCT
local @stRect:RECT
local @hDc
mov eax,uMsg

.if eax==WM_PAINT
invoke BeginPaint,hWnd,addr @stPs
mov @hDc,eax
invoke GetClientRect,hWnd,addr @stRect
invoke DrawText,@hDc,addr szText,-1,/
addr @stRect,/
DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint,hWnd,addr @stPs

.elseif eax==WM_CLOSE
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif

xor eax,eax
ret
_ProcWinMain endp
;主窗口创建
_WinMain proc
local @stWndClass:WNDCLASSEX
local @stMsg:MSG
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invoke LoadCursor,0,IDC_ARROW
;注册窗口
mov @stWndClass.hCursor,eax
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain
mov @stWndClass.hbrBackground,COLOR_WINDOW+1
mov @stWndClass.lpszClassName,offset szClassName
invoke RegisterClassEx,addr @stWndClass
;建立并显示窗口
invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,NULL,hInstance,NULL
mov hWinMain,eax
invoke ShowWindow,hWinMain,SW_SHOWNORMAL
invoke UpdateWindow,hWinMain
;消息循环
.while TRUE
invoke PeekMessage,addr @stMsg,NULL,0,0,PM_REMOVE
.break .if @stMsg.message==WM_QUIT
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.endw
ret
_WinMain endp
;主函数
start:
call _WinMain
invoke ExitProcess,NULL
end start
消息驱动的方法代替原始调用中断的方式,这种方式是Window特有的方式的,被一些专业人士称为API应用程序接口.
         当我谈及Win32汇编揭开了Window消息驱动,我兴奋不已.但是谈到这里我必须要谈到API的应用在C++的某一应用领域,也就是家喻户晓的MFC Windows.哈哈!谈到这里估计大家都晓得了吧!他的成就原本是开发C++基于Windows匹配的GDI设计.我以前的日志中不是谈到Visual Basic.Net的GDI设计吗?这里又谈及到完全调用API库的设计理念.看到这里大家不要糊涂了!给个实例就晓得了!
这是段MFC的启蒙程序,与上面的程序相互呼应,你们就能看出眉目来.

看看这段C++ 的MFC Windows编程:
Hello.h
class CMyApp:public CWinApp
{
public:
virtual BOOL InitInstance();
};
class CMainWindow:public CFrameWnd
{
public:
CMainWindow();
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
};

Hello.cpp
#include <afxwin.h>
#include "Hello.h"
CMyApp myApp;
BOOL CMyApp::InitInstance()
{
m_pMainWnd=new CMainWindow();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
CMainWindow::CMainWindow()
{
Create(NULL,_T("The Hello Application"));
}
void CMainWindow::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(rect);
dc.DrawText(_T("Hello,MFC"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
}
这和上面得汇编好像有天壤之别!可惜他们确实是都是在执行同一个界面.无非只是一个利用消息驱动,却为触及消息驱动的核心,所以在用其他语言编程时,我们只是调用API函数.甚至在我编写的Java和Visual Basic.Net用到得API少之又少.C语言中见不到API的影子.而C++的MFC中却大力鼓吹API.
        但是我不仅仅在关心Windows特有的消息驱动的方式外,我只是质疑从早先比尔.盖茨推出的DOS操作系统,到如今的MS-Windows之间具有翻天覆地的变化,还记得课本上大谈特谈CISC和RISC吗?还有那些复杂的流水线系统.在特定时期微软总是能够给我们惊喜.看看80186系统吧!到如今的80586之间吧!Intel增加了不少指令集MMX,SSE,而AMD也推出了3D Now!强大的指令集!其实这所有都是汇编的功劳.这些指令集!可能我会在以后谈及到.
       当80386处理器推出后,可寻址的范围到达了4GB,而驻留在每1MB空间的主存空间的能够被应用程序使用的空间不足600KB,我们试想DOS操作系统的内存的使用情况.DOS系统运行于实模式中,由于8086处理器的寻址范围又有1MB,当时系统硬件使用的存储器地址被安排在高端,地址是从A0000h(即640KB)开始的384KB中,其中有用于显示的视频缓冲区和BIOS缓冲区的地址空间.而在内存低端,安排了中断向量表和BIOS数据区;剩下从500开始到A0000h总共不到640KB的内存是操作系统和应有程序所能够使用的;应用程序不可能使用这640KB以外的内存.这就是著名的"640KB限制".如下图:
                                                      
而即使在这640KB中,DOS操作系统又占领了低端的一部分内存,最后剩下600KB左右的内存才是应用程序真正可以用的.这就是为什么在Windows中我们又是无法完全提升计算机的执行速度.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值