Linux内核如何“监听” C库?

问题描述 投票:2回答:2

我正试图为Linux内核和用户空间中的工作原理建立一个“全局”,我很困惑。我知道用户空间利用系统调用与内核“对话”,但是我不知道如何。我试图阅读C库和内核源代码,但是它们很复杂并且不容易理解。我也读过几本关于操作系统的概念性事实的书,例如管理进程,内存,设备,但是它们并不能使“转换”(用户空间->内核)变得清晰。那么,用户空间和内核空间之间的转换究竟发生在哪里? C库如何运行计算机中运行的Linux内核中的代码?

打个比方:假设有一所房子。房子被锁了。打开房子的钥匙在房子里面。屋子里只有一个人,内核。用户空间是试图进入房屋的人。我的问题是:内核如何知道房子外面有人要这个钥匙,以及哪种机制可以用那个钥匙打开房子?

c linux-kernel system-calls userspace
2个回答
11
投票

这很简单-人们可以使用门铃让内核知道它在外面等着。在我们的情况下,这个门铃通常是特殊的CPU异常,软件中断或允许用户空间应用程序使用且内核可以处理的专用指令。

所以过程是这样的:

  1. 首先,您需要知道系统电话号码。每个系统调用都有其唯一编号,内核内部有一个表,用于将这些编号映射到特定功能。每个体系结构都有不同的表,但表的数目相同。在两种不同的体系结构上,可能映射执行不同的系统调用。
  2. 然后您设置参数。这也是特定于体系结构的,但与在常规函数调用之间传递参数没有太大区别。通常,您会将参数放在特定的[[CPU寄存器中。在此体系结构的ABI中对此进行了描述。
  3. 然后输入syscall。根据体系结构,这可能意味着导致某些异常或使用专用的CPU指令。
  4. 内核具有特殊的处理程序功能,该功能在调用syscall时以内核模式运行。它将暂停进程执行,存储特定于该进程的所有信息(称为context switch),读取syscall编号和参数并调用适当的syscall例程。它还将确保将返回值放在适当的位置,以供用户空间读取,并在完成syscall例程(恢复其上下文)后安排回退进程。
  • 作为示例,要让内核知道您要在

    x86_64上调用syscall,可以在sysenter寄存器中使用带有syscall编号的%rax指令。使用寄存器(如果我没记错的话)传递参数%rdi%rsi%rdx%rcx%r8%r9

    您还可以使用在[[32位x86 CPU上使用的较早的方式-软件中断号0x80(int 0x80指令)。再次,在%rax寄存器中指定系统调用号,然后将参数转到(同样,如果我没记错的话)%ebx%ecx%edx%esi%edi%ebp。 >

    ARM非常相似-您将使用“主管调用”指令(SVC #0)。您的系统调用号将进入r7寄存器,所有参数将进入寄存器r0-r6,并且系统调用的返回值将存储在r0中。

    其他体系结构和操作系统使用类似的技术。详细信息可能有所不同-软件中断号可能不同,可能使用不同的寄存器甚至使用堆栈来传递参数,但核心思想是相同的。

  • 1
    投票
    © www.soinside.com 2019 - 2024. All rights reserved.