李治军操作系统学习(三)——系统调用的实现


前言

系统调用是如何通过操作系统使用硬件设备的

一、“直观”理解系统调用

  • 应用程序在内存中,操作系统也在内存中,若要让应用程序使用操作系统中的一段数据,为什么不能直接用jmp或mov从操作系统中调出数据呢?

原因是不安全,这样别人的程序可随意访问计算机上的敏感内容。

那如何阻止应用程序直接通过jmp或mov进入操作系统内核?应用程序如何正规地使用操作系统?


二、如何阻止应用程序jmp

在这里插入图片描述

  • 硬件阻止应用程序随意访问操作系统,操作系统与硬件紧密联系

硬件将内存分割成多个区域,主要分割为用户段和核心段。核心段与用户段的特权等级不同,核心段特权等级是在head.s初始化GDT时保存在表项所代表的地址中,被置为0。当退出系统内核使用用户程序时,用户程序的特权等级会置为3,用户段下的应用程序的特权等级均为3。

若应用程序想要进入系统内核,应用程序的地址存于CS中,CS的低两位为3,而要访问内核需通过GDT,GDT表项地址的低两位为0,硬件一检查0<3,就实现了阻止访问。

三、计算机允许通过中断进入内核

  • 设计了中断,允许应用程序进入内核,实际通过int 0x80进入内核

在这里插入图片描述
因为进入操作系统的唯一方法是中断,所以系统调用就是用户程序中的一段包含int指令的代码。

例如open函数,open展开成一段int指令,操作系统提供中断处理函数,中断处理函数根据是哪种中断执行相应代码。

1.如何从用户程序编程int指令

在这里插入图片描述
以printf为例,首先在C程序中使用printf,库函数会将printf的内容转换,提供write函数需要的参数,接着调用write函数,变成包含int 0x80中断的代码,这个中断代码通过系统调用进入操作系统。

  • 如何从write变为包含中断的代码

在这里插入图片描述
通过调用库函数printf将应用程序的prinf转换后,可得到write需要的一些参数,write库函数是用宏展开成一段汇编代码(C内嵌汇编)。具体步骤为首先使用_syscall3,给宏需要的参数赋值,有

type=int; 
name=write; 
atype=int; 
a=fd; 
btype=const; 
b=char *buf; 
ctype=off_t; 
c=const

接着在内嵌汇编中使用中断int 0x80,在此之前将__NR_write赋值给eax,接着将一系列参数赋值给其他寄存器,而__NR_write是整数4,也称系统调用号,通过系统调用号区分是read、write还是open。总体上将系统调用号置给eax,然后调用int 0x80进入系统内核。

2. 中断处理函数的细节

int 0x80会从idt表中跳转到中断处理函数处,运行完中断处理函数后再返回中断处。idt表会在操作系统初始化时被初始化,表项中存放中断处理函数的地址,且表项中的dpl会初始化为3。

应用程序运行时的cpl是3,而idt表项里的dpl也是3,因而应用程序可以通过int 0x80访问idt表项中的中断处理程序地址。这个地址的CS=8,意味着此时的cpl为0(CS后两位),因而中断处理函数的特权等级就最高,什么都能做。

  • 中断处理程序system_call内部实现

在这里插入图片描述

红色部分的_sys_call_table表的起始地址,表内记录了各种不同的系统调用对应的函数,由于每个系统调用函数入口地址占4个字节,eax是之前的__NR_write且等于4,因而访问的地址是_sys_call_table + 4 * eax。

在这里插入图片描述
由上图可见_sys_call_table确实是函数指针表。


总结

用户调用的printf,首先通过库函数编程int 0x80代码,int 0x80会根据idt跳转到中断处理函数system_call,system_call查表sys_call_table,根据eax的值和表地址查找到系统调用函数的入口地址,最后调用用户想要使用的系统函数。

整个系统调用的基本过程如下:

  • 应用程序调用库函数(API);
  • API 将系统调用号存入 EAX,然后通过中断调用使系统进入内核态;
  • 内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用);
  • 系统调用完成相应功能,将返回值存入 EAX,返回到中断处理函数;
  • 中断处理函数返回到 API 中;
  • API 将 EAX 返回给应用程序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值