c++ 调用dll_计算机自制操作系统(二九):系统调用API

6005b7866c0f9e3162f890467034bbb9.png

一、操作系统系统调用

每个操作系统都要向应用程序提供系统调用的API,那么什么是操作系统系统调用呢?这里不下定义,我们从具体的实例就可以明白。在DOS系统下编过程的人都知道,操作系统有很多系统调用,也称DOS功能调用或DOS中断,最经典的是:我们要在屏幕上显示一个字符串,用到的系统调用方法和原理如下:

cdfe81ea3af297fb7f15b1748819a701.png
DOS系统调用API

有比如Linux操作系统,它提供了200多个系统调用,通过汇编指令int 0x80实现,用系统调用号来区分入口函数。

35aa51a781f21abd9d40e9df5573168c.png
Linux系统调用API

但是作为视窗操作系统Windows提供的API方式就可以上面两种“命令行式”的操作系统不太一样,DOS和Lunix提供的系统调用一般叫软中断,使用软中断需要对各类寄存器预埋设置,过程会相当的繁琐和复杂。比如,都希望最好能把上面int 21h/ah=9的调用写成下面这样:

call PrintString,addr szHello

好消息出来了,Win32环境中的编程接口就是这个样子,这就是Windows API。而WIN32提供的系统调用那才叫真正的API,它实际上是以一种新的方法替代了DOS软中断的方式。

和DOS的结构相比,Win32的系统功能模块放在Windows的动态链接库(DLL)中。DLL是一种Windows的可执行文件,采用的是和 .exe文件同样的PE格式。在PE格式文件头的导出表中,以字符串形式指出了这个DLL能提供的函数列表。应用程序使用字符串类型的函数名指定要调用的函数。实际上,Win32的基础就是由DLL组成的。Win32 API的核心由3个DLL提供:

  • KERNEL32.DLL——系统服务功能。包括内存管理、任务管理和动态链接等。
  • GDI32.DLL——图形设备接口。利用VGA与DRV之类的显示设备驱动程序完成显示文本和矩形等功能。
  • USER32.DLL——用户接口服务。建立窗口和传送消息等。

当然,Win32 API还包括其他很多函数,这些也是由DLL提供的,不同的DLL提供了不同的系统功能。如使用TCP/IP协议进行网络通信的DLL是Wsock32.dll,它所提供的API称为Socket API;专用于电话服务方面的API称为TAPI(Telephony API),包含在Tapi32.dll中。所有的这些DLL提供的函数组成了现在所用的Win32编程环境。

我的理解是Windows之所以提供众多且复杂的API,一方面是方便用户,另一方面是作为视窗操作系统的鼻祖,它确实太复杂了,必须要足够的API才能支持应用程序的开发。Windows系统是行业大佬,我们的操作系统API不可能和它比肩,因此我们仿照Dos和Linux操作系统的API原理,照葫芦画瓢的做出自己的系统调用API:操作系统命名为JiangOS,我们规定自己的操作系统可执行文件的扩展名:HRB,并且这个可执行文件暂时以纯二进制机器代码存在,不像DosWindows对可执行文件做PE格式或Linux做ELF格式的任何封装。

2cf2f16b2441ec31ee96232d81390c26.png
自制的操作系统API

我们现在的任务就是在操作系统内核里做出这个系统调用API:INT 0x40。它的入口参数是:

EDX=2, 表示显示字符串的功能选项。

EBX=BUF,用来放置字符串的缓冲区地址。

二、保护模式INT中断调用

在做API之前,必须要需要补充一个比较重要的知识点:保护模式下的INT中断调用。大部分的人都知道保护模式下BIOS中断已经无法再使用了,因为在保护模式下,系统会有新的IDT中断机制,实模式下INT 0xXX中断模式已经失效。但是,鲜有人知道的是:其实在保护模式下,INT中断指令是没有失效的。也就是说 INT 0xXX可以继续使用,只不过处理器遇到这个指令的时候,不是像在实模式下根据XX去先搜素中断向量,进而根据中断向量最终转到BIOS的中断服务程序区。它是直接去IDT区搜素中断服务程序入口,也即保护模式下的中断机制。

所以,保护模式下,INT 0xXX指令不但可以继续使用,而且我们还可以利用它来做很多有用的事情。下面我们就来测试一下,利用INT 0xXX指令做有益的事情。

我们自制操作系统,其实有一个比较重要的问题就是需要捕获各种CPU发生的内部陷阱错误,比如程序如果发生了堆栈区溢出,系统就会崩溃,因此应该部署好这样的监控:一旦发生这样的情况应该立即报警。下面我们通过一个例子来看如何建立这种机制。

处理器在做除法的时候, 如果除数为0,会引发0号陷阱门中断。现在我们故意编写一个除数为0的程序,并提前准备好相应的中断服务程序,使之产生处理器器错误报警窗口。为此我们在C语言主程序中,准备一个函数diverror()来触发这样一个错误中断:

void diverror(int a,int b)
{ int d=0;
  a=10;
  b=0;
  d=a/b;
}

但一般这样一个函数在C编译器中是无法通过的,因为编译器会很聪明的提示你:除数为0。所以,我们得换一种方法:把diverror这个函数写在汇编语言中,让C语言直接调用即可:

;汇编程序
_diverror:
int 0x00        ;触发0号陷阱门中断
ret

既然C程序无法制造除数为0的陷阱,那么我们就在汇编语言里面用关键指令来触发:

int 0x00

这个指令的意思是告诉CPU,现在有除数为0的事情发生了,你赶紧去处理。CPU接收到这个信号之后,就会去IDT区寻找中断索引号 0x00的对应中断服务程序入口,那么我们需要提前准备好这个中断服务程序以及将它注册进IDT:

#define  IntNO_div  0x00;
resetidt(IntNO_div,  (int) asm_inthandler00); 
/*注册
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值