Linux 中的系统调用是如何实现的?

How is the system call in Linux implemented?

提问人:MainID 提问时间:2/1/2009 最后编辑:John BokerMainID 更新时间:3/22/2016 访问量:39565

问:

当我在用户模式下调用系统调用时,该调用在操作系统中是如何处理的?

它是否调用一些可执行的二进制文件或一些标准库?

如果是,完成通话需要什么样的东西?

Linux 操作系统

评论


答:

3赞 tvanfosson 2/1/2009 #1

大大简化了,但是当您尝试访问保留的内存地址时,会发生中断。中断将上下文切换到内核模式,并代表用户执行内核代码(实际系统调用)。调用完成后,控制权将返回给用户代码。

评论

0赞 MainID 2/1/2009
内核代码是什么样的,可执行二进制文件,汇编文件或动态链接库?
0赞 tvanfosson 2/1/2009
内核是系统上运行的内核,即内存中的操作系统映像。
53赞 GregD 2/1/2009 #2

看看这个

从版本 2.5 开始,linux 内核引入了新的系统调用 奔腾 II+ 上的进入机制 处理器。由于性能问题 在具有现有 软件中断方法, 备用系统调用条目 机制是使用 SYSENTER/SYSEXIT 指令 在奔腾 II+ 处理器上可用。 本文探讨了这个新的 机制。讨论仅限于 x86 架构和所有源代码 列表基于 Linux 内核 2.6.15.6.

  1. 什么是系统调用?

    系统调用提供用户空间 处理请求服务的方式 从内核。什么样的 服务业?托管的服务 通过操作系统,如存储, 内存、网络、进程管理 等。例如,如果用户进程 想要读取文件,它必须 进行“打开”和“读取”系统调用。 通常不调用系统调用 直接通过流程。C 库 提供所有系统的接口 调用。

  2. 系统调用中会发生什么?

    内核代码片段在 用户进程的请求。此代码 在环 0 中运行(具有当前权限 级别 -CPL- 0),这是最高的 x86 中的特权级别 建筑。所有用户进程均运行 在环 3 (CPL 3) 中。

    所以,要实现系统调用机制,我们需要的是

    1) 一种从环 3 调用环 0 代码的方法。

    2)一些内核代码来为请求提供服务。

  3. 很好的老式方法

    直到一段时间前,linux 曾经 在所有 x86 上实现系统调用 使用软件中断的平台。 要执行系统调用,用户进程 将复制所需的系统呼叫号码 添加到 %eax 并将执行 'int 0x80'。 这将产生中断0x80和 中断服务例程将是 叫。对于中断0x80,这个 例程是“所有系统调用 处理“例行公事。此例程将 在环 0 中执行。这个例程,作为 在文件中定义 /usr/src/linux/arch/i386/kernel/entry。S, 将保存当前状态并调用 基于适当的系统调用处理程序 在 %eax 中的值上。

  4. 新的闪亮方式

    结果发现,这个软件 中断方法的速度要慢得多 奔腾 IV 处理器。为了解决这个问题 问题,Linus 实现了一个 替代系统调用机制 利用 SYSENTER/SYSEXIT 所有奔腾提供的说明 II+ 处理器。在继续之前 有了这种新的方法,让我们 让自己更熟悉 这些说明。

评论

0赞 Weipeng 6/1/2022
感谢您将其置于历史背景下!
4赞 Eduard - Gabriel Munteanu 2/1/2009 #3

它通过glibc,glibc在用参数填充寄存器后发出0x80中断。然后,内核的中断处理程序在 syscall 表中查找 syscall 并调用相关的 sys_*() 函数。

16赞 wj32 2/1/2009 #4

这取决于你所说的系统调用是什么意思。您的意思是 C 库调用(通过 glibc)还是实际的系统调用?C 库调用最终总是以系统调用结束。

进行系统调用的旧方法是通过软件中断,即指令。Windows 有,而 Linux 有 .操作系统在中断描述符表 (IDT) 中为 0x2e 或 0x80设置中断处理程序。然后,此处理程序执行系统调用。它将参数从用户模式复制到内核模式(这由特定于操作系统的约定控制)。在 Linux 上,参数使用 、 、 和 传递。在 Windows 上,参数是从堆栈中复制的。然后,处理程序执行某种查找(以查找函数的地址)并执行系统调用。系统调用完成后,指令将返回到用户模式。intint 0x2eint 0x80ebxecxedxesiediiret

新的方式是 和 .这两个指令基本上为您完成了所有寄存器工作。操作系统通过型号特定寄存器 (MSR) 设置指令。之后,它实际上与使用 .sysentersysexitint

评论

0赞 Mywiki Witwiki 1/12/2013
“C 库调用最终总是以系统调用结束。” -- 有没有参考?
3赞 Yam Marcovic 1/19/2013
@MywikiWitwiki 不是任何 C 库调用,但调用 ,等等。它们可能不存在的唯一原因 - 如果它们甚至存在 - 是由于极其专业的优化。你可以假设它们总是进入内核模式,除非你是具有创新见解的内核专家。readwrite
1赞 Deepthought 7/17/2012 #5

程序集中的 int X 转换为系统调用号 n。例如,读取系统调用可以被赋予数字 4。

在系统启动时,操作系统会构建一个称为中断描述符表 (IDT) 的指针表,其中包含系统调用的地址列表以及执行它们所需的权限。
当前权限级别 (CPL) 保存在 CS 寄存器的一个位中(在 x86 上技术上为 2 位)。
以下是 int 指令遵循的步骤:
• 从 IDT 获取第 n 个描述符,其中 n 是 int 的参数。 • 检查 %cs 中的 CPL 是否为 <= DPL,其中 DPL 是描述符中的权限级别。

• 如果不是,则用户没有足够的权限来执行此操作,并将导致执行 int 13 指令(一般保护错误),(用户没有足够的权限)
• 如果是,则用户代码有足够的权限来执行此系统调用,保存当前执行上下文(寄存器等),因为我们现在切换到内核模式。
这些信息包括寄存器、标志,因为当系统调用结束时,我们希望从离开的地方继续执行。 • 系统调用的参数保存在内核堆栈上,因为系统调用是在内核模式下执行的。

VSYSCALL(快速系统调用) 每次用户执行系统调用时,操作系统都会保存机器的当前状态(即寄存器、堆栈指针等)
并切换到内核模式执行。对于某些系统调用,没有必要保存所有寄存器。例如,当天的 gettime 系统调用读取当前时间,系统调用返回。因此,一些系统调用是通过所谓的 vsyscalls 实现的。在这里,当进行系统调用时,它会在用户空间本身中执行,而无需切换到内核。因此节省了时间。
有关 vsyscall http://www.trilithium.com/johan/2005/08/linux-gate/ 的详细信息,请参阅此处
,任何人都可以了解 gettimeofday 的工作原理?

0赞 Chris Tsui 12/23/2013 #6

系统调用由特殊的陷阱指令、系统调用号和参数组成。

  1. 特殊的陷阱指令用于从用户模式切换到 内核模式,具有无限权限。
  2. 系统调用号和参数由寄存器传递。