系统调用
- 格式:ppt
- 大小:764.50 KB
- 文档页数:38
简介⼏种系统调⽤函数:write、read、open、close、ioctl 在 Linux 中,⼀切(或⼏乎⼀切)都是⽂件,因此,⽂件操作在 Linux 中是⼗分重要的,为此,Linux 系统直接提供了⼀些函数⽤于对⽂件和设备进⾏访问和控制,这些函数被称为系统调⽤(syscall),它们也是通向操作系统本⾝的接⼝。
⼀、系统调⽤ 系统调⽤就是 Linux 内核提供的⼀组⽤户进程与内核进⾏交互的接⼝。
这些接⼝让应⽤程序受限的访问硬件设备,提供了创建新进程并与已有进程进⾏通信的机制,也提供了申请操作系统其他资源的能⼒。
系统调⽤⼯作在内核态,实际上,系统调⽤是⽤户空间访问内核空间的唯⼀⼿段(除异常和陷⼊外,它们是内核唯⼀的合法⼊⼝)。
系统调⽤的主要作⽤如下:1)系统调⽤为⽤户空间提供了⼀种硬件的抽象接⼝,这样,当需要读写⽂件时,应⽤程序就可以不⽤管磁盘类型和介质,甚⾄不⽤去管⽂件所在的⽂件系统到底是哪种类型;2)系统调⽤保证了系统的稳定和安全。
作为硬件设备和应⽤程序之间的中间⼈,内核可以基于权限、⽤户类型和其他⼀些规则对需要进⾏的访问进⾏判断;3)系统调⽤是实现多任务和虚拟内存的前提。
要访问系统调⽤,通常通过 C 库中定义的函数调⽤来进⾏。
它们通常都需要定义零个、⼀个或⼏个参数(输⼊),⽽且可能产⽣⼀些副作⽤(会使系统的状态发⽣某种变化)。
系统调⽤还会通过⼀个 long 类型的返回值来表⽰成功或者错误。
通常,⽤⼀个负的值来表明错误,0表⽰成功。
系统调⽤出现错误时,C 库会把错误码写⼊ errno 全局变量,通过调⽤ perror() 库函数,可以把该变量翻译成⽤户可理解的错误字符串。
⼆、⼏种常⽤的系统调⽤函数2.1 write 系统调⽤ 系统调⽤ write 的作⽤是把缓冲区 buf 的前 nbytes 个字节写⼊与⽂件描述符 fildes 关联的⽂件中。
它返回实际写⼊的字节数。
如果⽂件描述符有错或者底层的设备驱动程序对数据块长度⽐较敏感,该返回值可能会⼩于 nbytes。
操作系统中系统调用实例
系统调用是操作系统内核提供给应用程序的接口,应用程序通过系统调用来访问操作系统内核提供的服务和资源,如文件、网络、内存、外设等。
下面是一个C语言中系统调用的实例:
```c
int read(int fd, void *buf, int count); //读文件数据
int write(int fd, const void *buf, int count); //写文件数据
int open(const char *pathname, int flags, mode_t mode); //打开文件
```
在这个例子中,`read`、`write`和`open`是系统调用的函数名称。
`fd`是文件描述符,`buf`是指向缓冲区的指针,`count`是要读取或写入的字节数。
`pathname`是文件的路径名,`flags`是打开文件的选项,`mode`是文件的访问模式。
系统调用的执行过程可以分为三个步骤:
1. 执行前的准备工作:包括模式切换和栈切换。
2. 执行处理程序(处理函数):这是系统调用的主要工作,根据系统调用的不同而有所差异。
3. 执行后的善后工作:包括模式切换和栈切换的回退。
不同的操作系统提供了各自的系统调用,但C语言标准库提供了一种通用的方式,使得C代码可以在不同的操作系统上运行,前提是经过不同操作系统编译器的编译。
Linux内核中系统调用详解什么是系统调用?(Linux)内核中设置了一组用于实现各种系统功能的子程序,称为系统调用。
用户可以通过系统调用命令在自己的应用程序中调用它们。
从某种角度来看,系统调用和普通的函数调用非常相似。
区别仅仅在于,系统调用由(操作系统)核心提供,运行于核心态;而普通的函数调用由函数库或用户自己提供,运行于用户态。
随Linux核心还提供了一些(C语言)函数库,这些库对系统调用进行了一些包装和扩展,因为这些库函数与系统调用的关系非常紧密,所以习惯上把这些函数也称为系统调用。
为什么要用系统调用?实际上,很多已经被我们习以为常的C语言标准函数,在Linux 平台上的实现都是靠系统调用完成的,所以如果想对系统底层的原理作深入的了解,掌握各种系统调用是初步的要求。
进一步,若想成为一名Linux下(编程)高手,也就是我们常说的Hacker,其标志之一也是能对各种系统调用有透彻的了解。
即使除去上面的原因,在平常的编程中你也会发现,在很多情况下,系统调用是实现你的想法的简洁有效的途径,所以有可能的话应该尽量多掌握一些系统调用,这会对你的程序设计过程带来意想不到的帮助。
系统调用是怎么工作的?一般的,进程是不能访问内核的。
它不能访问内核所占内存空间也不能调用内核函数。
(CPU)(硬件)决定了这些(这就是为什么它被称作"保护模式")。
系统调用是这些规则的一个例外。
其原理是进程先用适当的值填充(寄存器),然后调用一个特殊的指令,这个指令会跳到一个事先定义的内核中的一个位置(当然,这个位置是用户进程可读但是不可写的)。
在(Intel)CPU中,这个由中断0x80实现。
硬件知道一旦你跳到这个位置,你就不是在限制模式下运行的用户,而是作为操作系统的内核--所以你就可以为所欲为。
进程可以跳转到的内核位置叫做sysem_call。
这个过程检查系统调用号,这个号码告诉内核进程请求哪种服务。
然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。
系统调用调用门原理-概述说明以及解释1.引言1.1 概述系统调用是操作系统提供给应用程序使用的一种接口,它允许应用程序请求操作系统执行特定的功能或操作。
系统调用提供了应用程序与底层硬件和系统资源的交互方式,使得应用程序能够进行文件读写、网络通信、进程管理等操作。
调用门是一种机制,它可以让应用程序在用户态和内核态之间进行切换,从而实现对操作系统功能的访问。
调用门提供了一条特殊的指令,应用程序通过调用这条指令来进入内核态执行系统调用,完成需要操作系统权限才能进行的操作。
系统调用和调用门是操作系统中非常重要的概念和机制。
系统调用允许应用程序使用操作系统提供的功能,使得应用程序可以以一种安全又可控的方式访问系统资源。
调用门则是系统调用的一种实现方式,它提供了一种高效、可靠的切换机制,使得应用程序可以方便地进行系统调用,从而完成需要操作系统权限的操作。
在本文中,我们将详细介绍系统调用和调用门的原理和工作过程,探讨它们的应用场景和优势。
我们还将深入分析调用门的结构和运行机制,了解它在操作系统中的实现和使用。
最后,我们将对系统调用和调用门的重要性进行总结,并展望它们在未来的发展前景。
通过阅读本文,读者将能够更好地理解系统调用和调用门的作用和原理,为深入研究操作系统提供理论和实践基础。
【1.2 文章结构】本篇文章将从以下几个方面进行讲述系统调用和调用门的原理和应用。
首先,在引言中会概述整篇文章的主要内容和目的。
接下来,在正文部分,会详细介绍系统调用的定义和作用,包括其实现方式和分类,并对其优缺点进行探讨。
同时,还会对调用门进行概述,阐述其原理和工作过程,并介绍其在实际应用中的场景和优势。
最后,将重点解释调用门的原理,探讨引入调用门的背景,分析调用门的结构和运行机制,并讨论调用门的实现和使用。
在结论部分,会总结系统调用和调用门的重要性,并对其未来发展进行展望。
最后,以简短的结束语作为结尾,对文章内容进行总结。
通过以上的结构安排,本文将全面而系统地介绍系统调用和调用门的原理和应用,读者能够明确了解系统调用和调用门的概念、工作原理、应用场景及其未来发展前景。
系统调用实现过程系统调用是让用户态进入内核态的一种方法,系统调用的实现分为四部分:系统调用注册,系统调用触发,系统调用执行,系统调用返回。
1.系统调用注册在每种平台上,都有特定的指令可以使进程执行由用户态转换为内核态,这种指令称为操作系统陷入。
在Linux中是通过软中断来实现这种陷入的,在X86平台上,这条指令是int 0x80。
也就是说在linux中,系统调用的接口是一个中断处理函数的特例。
在linux启动过程中,对INT80进行一定的初始化:1.使用汇编子程序setup_idt(linux/arch/i386/kernel/head.S)初始化idt表(中断描述符表),这时所有的入口函数偏移地址都被设为ignore_int( setup_idt:lea ignore_int,%edxmovl $(__KERNEL_CS << 16),%eaxmovw %dx,%ax /* selector = 0x0010 = cs */movw $0x8E00,%dx /* interrupt gate - dpl=0, present */lea SYMBOL_NAME(idt_table),%edimov $256,%ecxrp_sidt:movl %eax,(%edi)movl %edx,4(%edi)addl $8,%edidec %ecxjne rp_sidtretselector = __KERNEL_CS, DPL = 0, TYPE = E, P = 1);2.Start_kernel()(linux/init/main.c)调用trap_init()(linux/arch/i386/kernel/trap.c)函数设置中断描述符表。
在该函数里,实际上是通过调用函数set_system_gate(SYSCALL_VECTOR,&system_call)来完成该项的设置的。
System-call系统调⽤⼀、系统调⽤过程1. ⽤户在进⾏系统调⽤时,通过传递⼀个系统调⽤编号,来告知内核,它所请求的系统调⽤,内核通过这个编号进⽽找到对应的处理系统调⽤的C函数。
这个系统编号,在 x86 架构上,是通过 eax 寄存器传递的。
2. 系统调⽤的过程跟其他的异常处理流程⼀样,包含下⾯⼏个步骤:(1) 将当前的寄存器上下⽂保存在内核 stack 中(这部分处理都在汇编代码中)(2) 调⽤对应的C函数去处理系统调⽤(3) 从系统调⽤处理函数返回,恢复之前保存在 stack 中的寄存器,CPU 从内核态切换到⽤户态3. 在内核中⽤于处理系统调⽤的C函数⼊⼝名称是 sys_xxx() ,xxx() 就是对应的系统调⽤,实际上会有宏在xxx()前⾯加上⼀个函数头。
在Linux 内核的代码中,这样的系统调⽤函数命名则是通过宏定义 SYSCALL_DEFINEx 来实现的,其中的 x 表⽰这个系统调⽤处理函数的输⼊参数个数。
(不同的架构会复写这个宏定义,以实现不同的调⽤规则,其中 ARM64 的宏定义在arch/arm64/include/asm/syscall_wrapper.h ⽂件中)4. 将系统调⽤编号与这些实际处理C函数联系起来的是⼀张系统调⽤表 sys_call_table 这个表具有 __NR_syscalls 个元素(⽬前kernel-5.10这个值是440)。
表中对应的 n 号元素所存储的就是 n 号系统调⽤对应的处理函数指针。
__NR_syscalls 这个宏只是表⽰这个表的⼤⼩,并不是真正的系统调⽤个数,如果对应序号的系统调⽤不存在,那么就会⽤ sys_ni_syscall 填充,这是⼀个表⽰没有实现的系统调⽤,它直接返回错误码 -ENOSYS。
//arch/arm64/kernel/sys.c#undef __SYSCALL#define __SYSCALL(nr, sym) asmlinkage long __arm64_##sym(const struct pt_regs *);#include <asm/unistd.h> //<1>#undef __SYSCALL#define __SYSCALL(nr, sym) [nr] = __arm64_##sym,typedef long (*syscall_fn_t)(const struct pt_regs *regs);const syscall_fn_t sys_call_table[__NR_syscalls] = {[0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall, //这个函数是防⽌没有实现的,直接return -ENOSYS;#include <asm/unistd.h> //<2>};<asm/unistd.h> 最终使⽤的是 <uapi/asm-generic/unistd.h> 它⾥⾯定义了 NR_xxx 和相关函数,以 getpriority 系统调⽤的实现为例://include/uapi/asm-generic/unistd.h#define __NR_getpriority 141__SYSCALL(__NR_getpriority, sys_getpriority)在位置<1>,展开为:asmlinkage long __arm64_sys_getpriority(const struct pt_regs *);在位置<2>,展开为:[141] = __arm64_sys_getpriority,最终 sys_call_table[] 下标为 141 的位置指向的函数为 __arm64_sys_getpriority⼆、系统调⽤的进⼊和退出1. 在 x86 的架构上,⽀持2种⽅式进⼊和退出系统调⽤:(1) 通过 int $0x80 触发软件中断进⼊,iret 指令退出(2) 通过 sysenter 指令进⼊,sysexit指令退出2. 在 ARM 架构上,则是通过 svc 指令进⼊系统调⽤。
如何处理代码中的系统调用错误处理代码中的系统调用错误是软件开发过程中不可避免的问题,它可能由于操作系统环境、外部资源、网络连接等原因导致。
在软件开发中,系统调用错误可能出现在不同的阶段,比如文件操作、网络连接、进程管理等。
解决系统调用错误的关键在于准确地识别错误的来源,然后有针对性地进行处理。
本文将从识别系统调用错误、处理系统调用错误两个方面展开讨论,希望能够在读者对此问题有一个全面的理解。
一、识别系统调用错误在处理系统调用错误之前,我们首先要准确地识别系统调用错误的来源,这样才能有针对性地进行处理。
系统调用错误的识别可以通过以下几个途径来进行:1.错误代码获取:在发生系统调用错误时,操作系统会返回一个错误代码,通过查阅操作系统的相关文档,我们可以找到对应的错误信息。
对于Unix/Linux系统,可以通过errno变量获取错误代码,对于Windows系统,可以通过GetLastError函数获取错误代码。
2.错误日志记录:在应用程序中添加错误日志记录的功能,当系统调用错误发生时,将错误信息写入日志文件,以便后续查找问题。
同时,也可以采用日志收集工具对错误日志进行分析。
3.调试工具使用:在开发过程中,我们可以使用一些调试工具,比如gdb、strace等,来跟踪系统调用的执行过程,以便及时发现问题所在。
二、处理系统调用错误当我们准确地识别了系统调用错误的来源之后,接下来就是对系统调用错误进行处理。
针对不同的系统调用错误,我们可以采取不同的处理措施,下面我们分别介绍一些常见的系统调用错误处理方法:1.重试:对于一些临时性的系统调用错误,比如网络连接失败、文件操作超时等,我们可以采取重试的方式来进行处理,可以通过设置重试次数、重试间隔等参数来控制重试的策略。
2.错误信息提示:对于一些用户操作或者命令行程序,在发生系统调用错误时,我们可以通过错误信息提示的方式来通知用户,以便用户能够准确地了解问题所在。
3.错误恢复:对于一些需要保证数据一致性的系统调用错误,比如数据库操作失败、文件写入失败等,我们可以采取一些恢复措施,比如回滚事务、释放资源等,以保证系统的正常运行。
简述系统调用的执行过程系统调用是操作系统中重要的一个部分,可以让应用程序与操作系统进行交互。
在执行系统调用的过程中,操作系统在内核态下运行,应用程序在用户态下运行。
本文将从执行系统调用的准备、转换到内核态、内核态下的处理、返回用户态以及错误处理等几个方面进行介绍。
在执行系统调用之前,应用程序需要将系统调用参数传递给操作系统。
这些参数通常包括系统调用号、参数列表等。
然后,应用程序通过软中断指令触发系统调用。
软中断指令会将处理器的状态切换到内核态。
一旦处理器进入内核态,操作系统开始执行相关的系统调用代码。
首先,操作系统会根据系统调用号确定要执行的操作,如读取文件、创建进程等。
然后,操作系统会在内核态下执行相关的操作,并返回结果。
在内核态执行过程中,操作系统会根据传入的参数执行相应的操作,如打开指定文件,读取指定的数据等。
此时,操作系统可以直接访问硬件资源和系统内存。
同时,操作系统也可以进行更高层次的管理工作,如进程调度和内存管理等。
执行完操作后,操作系统会将结果传递给应用程序,并将处理器状态切换回用户态。
此时,应用程序就可以继续执行自己的代码了,同时也可以根据操作系统返回的结果来判断操作是否成功。
当系统调用出现错误时,操作系统会返回相应的错误码给应用程序。
应用程序需要根据错误码进行相应的错误处理。
例如,如果创建文件失败,应用程序可以尝试修改文件权限或者改变文件名等方式来防止操作失败。
综上所述,系统调用是一个很重要的操作系统功能,可以让应用程序与操作系统进行交互。
在执行系统调用的过程中,应用程序需要将系统调用参数传递给操作系统,并通过软中断指令触发系统调用。
操作系统会在内核态下执行相关的系统调用代码,执行完操作后将结果传递给应用程序。
如果出现错误,操作系统会返回相应的错误码给应用程序进行错误处理。
库函数与系统调⽤的联系与区别⼀. 概念系统调⽤(:system call),指运⾏在的向请求某些服务的调⽤过程。
系统调⽤提供了⽤户程序与之间的接⼝。
⼀般来说,系统调⽤都在内核态执⾏。
由于系统调⽤不考虑平台差异性,由内核直接提供,因⽽移植性较差(⼏乎⽆移植性)。
库函数(library function),是由⽤户或组织⾃⼰开发的,具有⼀定功能的函数集合,⼀般具有较好平台移植性,通过库⽂件(静态库或动态库)向程序员提供功能性调⽤。
程序员⽆需关⼼平台差异,由库来屏蔽平台差异性。
⼆,区别调⽤※函数库调⽤ VS 系统函数库调⽤系统调⽤平台移植性好依赖于内核,不保证移植性调⽤函数库中的⼀段程序(或函数)调⽤系统内核的服务⼀个普通功能函数的调⽤是操作系统的⼀个⼊⼝点在⽤户空间执⾏在内核空间执⾏它的运⾏时间属于“⽤户时间”它的运⾏时间属于“系统”时间属于过程调⽤,调⽤开销较⼩在⽤户空间和内核上下⽂环境间切换,开销较⼤库函数数量较多UNIX中⼤约有90个系统调⽤,较少典型的C函数库调⽤:printf scanf malloc 典型的系统调⽤:fork open write三. 联系⼀般⽽⾔,跟内核功能与操作系统特性紧密相关的服务,由系统调⽤提供;具有共通特性的功能⼀般需要较好的平台移植性,故⽽由库函数提供。
库函数与系统调⽤在功能上相互补充,如进程间通信资源的管理,进程控制等功能与平台特性和内核息息相关,必须由系统调⽤来实现。
⽂件 I/O操作等各平台都具有的共通功能⼀般采⽤库函数,也便于跨平台移植。
某些情况下,库函数与系统调⽤也有交集,如库函数中的I/O操作的内部实现依然需要调⽤系统的I/O⽅能实现。
IO系统调用原理介绍
下面是IO系统调用的原理和流程介绍。
1. 用户程序发起IO请求:应用程序通过系统提供的IO相关函数发起IO请求。
例如,如果要读取文件,应用程序会调用read(函数,如果要写入文件,应用程序会调用write(函数。
2.系统调用进入内核态:当应用程序发起IO请求时,CPU会从用户态切换到内核态,将控制权交给操作系统内核。
3.内核处理IO请求:操作系统接收到IO请求后,会根据请求的类型和参数进行相应的处理。
4.硬件设备访问:操作系统根据IO请求的类型,调用相应的设备驱动程序,将IO请求传递给硬件设备进行处理。
例如,如果是读取文件的IO请求,操作系统会调用磁盘驱动程序将数据从硬盘读取到内存中。
5.等待IO操作完成:在进行IO操作时,可能需要等待硬件设备的响应。
例如,如果是网络IO请求,操作系统可能需要等待网络数据包的传输完成才能继续执行。
6.返回结果给应用程序:当IO操作完成后,操作系统将结果返回给应用程序。
如果是读取文件的请求,操作系统会将读取到的数据拷贝到应用程序指定的缓冲区。
7.应用程序继续执行:一旦IO操作完成并且结果返回给应用程序,操作系统会将控制权重新切换回用户态,应用程序可以继续执行后续的操作。
IO系统调用的原理可以简单总结为:应用程序通过系统调用将IO请求交给操作系统内核,内核根据IO请求类型和参数进行相应的处理,并将请求传递给硬件设备进行实际的IO操作。
当IO操作完成后,操作系统将结果返回给应用程序,应用程序可以根据结果继续执行后续的操作。
操作系统和系统调用的关系
操作系统是一个计算机系统中的核心程序,负责管理和控制系统硬件和软件的运行。
而系统调用是操作系统提供给应用程序的一种接口,它允许应用程序通过操作系统访问系统资源和服务,如文件操作、网络连接、进程管理等。
操作系统通过提供系统调用接口来控制和管理系统资源,例如,当一个进程向操作系统请求打开一个文件时,它将调用系统调用来让操作系统执行打开文件的操作。
系统调用实现了进程与操作系统之间的通信,允许应用程序使用操作系统的功能和服务。
因此,可以说操作系统和系统调用是相互关联的,系统调用是应用程序通过操作系统访问系统资源和服务的方法,操作系统通过系统调用实现对系统资源和服务的管理和控制。
open系统调用的参数open系统调用是在操作系统中用于打开文件或创建新文件的函数。
它的参数包括文件名、打开模式和权限。
1. 文件名,open系统调用的第一个参数是一个字符串,表示要打开或创建的文件名。
文件名可以是绝对路径或相对路径,可以包含文件的目录结构和文件名本身。
2. 打开模式:open系统调用的第二个参数是一个整数,表示打开文件的模式。
常见的打开模式包括:O_RDONLY,只读模式,打开文件后只能读取文件内容。
O_WRONLY,只写模式,打开文件后只能写入文件内容,如果文件不存在则创建新文件。
O_RDWR,读写模式,打开文件后可以读取和写入文件内容。
O_CREAT,如果文件不存在则创建新文件。
O_APPEND,在文件末尾追加内容而不是覆盖原有内容。
3. 权限:open系统调用的第三个参数是一个整数,表示文件的权限。
权限规定了文件的所有者、所属组和其他用户对文件的访问权限。
常见的权限参数包括:S_IRUSR,文件所有者的读权限。
S_IWUSR,文件所有者的写权限。
S_IXUSR,文件所有者的执行权限。
S_IRGRP,文件所属组的读权限。
S_IWGRP,文件所属组的写权限。
S_IXGRP,文件所属组的执行权限。
S_IROTH,其他用户的读权限。
S_IWOTH,其他用户的写权限。
S_IXOTH,其他用户的执行权限。
除了这些基本参数外,open系统调用还可以接受一些额外的参数,用于设置文件的属性和行为。
例如,可以通过设置O_TRUNC参数来截断文件内容,或者通过设置O_NONBLOCK参数来将文件设置为非阻塞模式。
需要注意的是,open系统调用的返回值是一个文件描述符(file descriptor),它是一个非负整数,用于标识打开的文件。
文件描述符可以用于后续的读取、写入和关闭操作。
总结起来,open系统调用的参数包括文件名、打开模式和权限,可以通过设置额外的参数来调整文件的属性和行为。
你真的知道什么是系统调⽤吗?你真的知道什么是系统调⽤吗?在现代操作系统⾥,由于系统资源可能同时被多个应⽤程序访问,如果不加保护,那各个应⽤程序之间可能会产⽣冲突,对于恶意应⽤程序更可能导致系统奔溃。
这⾥所说的系统资源包括⽂件、⽹络、各种硬件设备等。
⽐如要操作⽂件必须借助操作系统提供的api(⽐如linux下的fopen)。
系统调⽤在我们⼯作中⽆时⽆刻不打着交道,那系统调⽤的原理是什么呢?在其过程中做了哪些事情呢?本⽂将阐述系统调⽤原理,让⼤家对于系统调⽤有⼀个清晰的认识。
概述现代cpu通常有多种特权级别,⼀般来说特权级总共有4个,编号从Ring 0(最⾼特权)到Ring 3(最低特权),在Linux上之⽤到Ring 0和RIng 3,⽤户态对应Ring 3,内核态对应Ring 0。
普通应⽤程序运⾏在⽤户态下,其诸多操作都受到限制,⽐如改变特权级别、访问硬件等。
特权⾼的代码能将⾃⼰降⾄低等级的级别,但反之则是不⾏的。
⽽系统调⽤是运⾏在内核态的,那么运⾏在⽤户态的应⽤程序如何运⾏内核态的代码呢?操作系统⼀般是通过来从⽤户态切换到内核态的。
学过操作系统课程的同学对中断这个词肯定都不陌⽣。
中断⼀般有两个属性,⼀个是中断号,⼀个是中断处理程序。
不同的中断有不同的中断号,每个中断号都对应了⼀个中断处理程序。
在内核中有⼀个叫中断向量表的数组来映射这个关系。
当中断到来时,cpu会暂停正在执⾏的代码,根据中断号去中断向量表找出对应的中断处理程序并调⽤。
中断处理程序执⾏完成后,会继续执⾏之前的代码。
中断分为硬件中断和软件中断,我们这⾥说的是软件中断,软件中断通常是⼀条指令,使⽤这条指令⽤户可以⼿动触发某个中断。
例如在i386下,对应的指令是int,在int指令后指定对应的中断号,如int 0x80代表你调⽤第0x80号的中断处理程序。
中断号是有限的,所有不会⽤⼀个中断来对应⼀个系统调⽤(系统调⽤有很多)。
Linux下⽤int 0x80触发所有的系统调⽤,那如何区分不同的调⽤呢?对于每个系统调⽤都有⼀个系统调⽤号,在触发中断之前,会将系统调⽤号放⼊到⼀个固定的寄存器,0x80对应的中断处理程序会读取该寄存器的值,然后决定执⾏哪个系统调⽤的代码。