系统调用原理---程序员的自我修养读书笔记

本文详细介绍了系统调用的原理,包括特权级的概念,用户态与内核态的切换,以及如何通过中断从用户态进入内核态执行系统调用。特别讨论了在x86架构下的Linux系统中,系统调用如何通过int 0x80指令触发,中断处理程序如何找到对应的系统调用函数,并在内核中执行。此外,还提到了系统调用参数的传递方式和内核栈的切换过程。
摘要由CSDN通过智能技术生成
特权级和中断
现代操作系统中,通常有两种特权级别,分别为用户模式(User Mode)和内核模式(Kernel Mode),也被称为用户态和内核态。由于有多种特权模式的存在,操作系统就可以让不同的代码运行在不同的模式上,以限制它们的权力,提高稳定性和安全性。普通应用程序运行在用户态的模式下,诸多操作系统受到限制,这些操作包括访问硬件设备,开关中断,改变特权模式等。
运行在高特权级的代码将自己降至低特球级是允许的,但反过来则不是轻易进行的。在将低特权级的环境转为高特权级时,需要使用一种较为受控和安全的形式,以防止低特权级模式的代码破坏高特权级模式代码的执行。
系统调用是运行在内核态的,而应用程序基本都是运行在用户态的。用户态的程序如何运行内核态的代码——通过中断(interrupt)来从用户态切到内核态。中断时一个硬件或软件发出的请求,要求CPU暂停当前的工作转去处理更加重要的事情。举个例子,当你在编辑文本时候,键盘上的键不段被按下,CPU通过一种轮询(Poll)方法,每隔一小段时间去询问键盘是否按下,但除非用户是疯狂打字员,否则大部分的轮询行为得到的都是没有键按下的回应,这样就浪费资源了。另一种就是CPU不去理键盘,而当键盘上有键被按下时,键盘上的芯片发送一个信号给CPU,CPU接收到信号之后就知道键盘被按下了,然后再去询问键盘被按下哪个键是哪一个。这样的信号就是一种中断。
中断一般具有两个属性,一个称为中断号(从0开始),一个称为中观处理程序(interrupt service rontine,ISR)。不同的中断具有不同的中断号,而同时一个中断处理程序一一对应一个中断号。在内核中,有一个数组称为中断向量表(interrupt vector table),这个数组的第n项包含了指向第n号中断的中断处理程序的指针。当中断来时,CPU会暂停当前执行的代码,根据中断的中断号,在中断向量表中找到对应的中断处理程序,并调用它。
通常意义上,中断有两种类型,一种称为硬件中断,这种中断来自于硬件的异常或其他事件的发生,如电源掉电,键盘被按下等。 另一种称为软件中断,软件中断通常是一条指令(i386下是int),带有一个参数记录中断号,使用这条指令用户可以手动触发某个中断并执行其中断处理程序。 例如在i386下,int0x80这条指令会调用地0x80号中断的处理程序。
由于中断号是很有限的,操作系统不会舍得用一个中断号来对应一个系统调用,而更倾向与用一个或少数几个中断号来对应所有的系统调用。例如,在i386下Windows里绝大多数系统调用都是由int 0x2e来触发的,而Linux则使用int 0x80来触发所有的系统调用。对于同一个中断号,操作系统如何知道是哪一个系统调用呢?系统调用都有一个系统调用号,就像身份标识一样来表明哪一个系统调用,这个系统调用号通常就是系统调用在系统调用表中的位置,例如Linux里fork的系统调用号是2。这个系统调用号在执行int指令前会被放置在某个固定的寄存器里,对应的中断代码会取得这个系统调用号,并且调用正确的函数。以Linux的int 0x80为例,系统调用号是由eax来传入的。用户将系统调用号放入eax,然后使用int 0x80调用中断,中断服务程序就可以从eax里取得系统调用号,进而调用对应的函数。
基于int的Linux的经典系统调用实现
了解到当应用程序调用系统调用时,程序时如何一步步进入操作系统内核调用相应函数的。例如,fork为例子的Linux系统调用的执行流程。

1,触发中断
首先当程序在代码里调用一个系统调用时,是以一个函数的形式调用的,例如程序调用fork:
int main(){
fork();
}
fork函数是一个对系统调用sys_fork的封装,可以用宏来定义它:
_syscall0(pid_t, fork);
_syscall0是一个宏函数,用于定义一个没有参数的系统调用的封装。它的第一个参数为这个系统调用的返回值类型,这里为pid_t,是一个Linux自定义的类型,代表进程的ID。_syscall0的第二个参数是系统调用的名称,_syscall0展开之后会形成一个与系统名称同名的函数。下面的代码时i386版本的syscall0定义:
#define _syscall0(type, name)
type name(void)
{
long __res;;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (__NR_##name));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值