系统调用是否直接发送到内核?

时间:2018-02-13 12:38:00

标签: c linux linux-kernel posix libc

我有几个假设,很可能其中一些是不正确的。请纠正我的错误。

我们可以将用C编写的程序中的函数分类如下:

  • 发送到动态加载库的函数:

    1. 将这些文件发送到库,将它们转换为多个标准C函数
    2. 库将它们传递给libc,在那里它们被转换为多个系统调用。
    3. Libc将这些内容传递给执行它们的内核,并将返回值发送回libc。
    4. Libc将收集returs,通过c-function对它们进行分组,并使用它们为每个c函数创建1个返回值。这些返回将被发送回动态加载的库。
    5. 此库将收集所有返回并使用它们创建1返回原始程序。
  • 在代码中定义的函数或静态编译库的一部分:所有内容与上面的类别相同,但是:

    1. 他们的程序已经将其转换为已知的标准C函数,或者转换为在另一种情况下调用动态加载库的函数。
    2. 标准c函数发送到libc,其他函数发送到动态加载的库(它们将按上述方式处理)。
    3. 基于两种类型功能的回报创建1个最终报表将由程序
    4. 完成
  • 标准C函数的函数:它们将被发送到libc,它将以与上面相同的方式与内核通信,并且1将返回到程序

  • 系统调用的函数:它们不会直接发送到内核,但必须传递给libc,尽管它不会做任何额外的工作。

安全检查(权限,写入未分配的内存,...)总是由内核完成,尽管上面的libc和库也可能先检查它。

所有符合POSIX标准的系统都遵循这些规则

2 个答案:

答案 0 :(得分:2)

在Linux和其他一些POSIX系统(如FreeBSD)上可能不一样。

在Linux上,ABI定义了系统调用的完成方式。阅读Linux kernel interfaces。系统调用列在syscalls(2)中(但另请参阅/usr/include/asm*/unistd.h ...)。另请阅读vdso(7)assembler HowTo解释了更多细节,但仅限于32位i686。

大多数Linux libc都是免费软件,你可以研究它们的源代码。恕我直言musl-libc的源代码非常易读。

为了简化一点点,大多数系统调用(例如write(2))都是libc中的小C函数,其中:

  1. 使用SYSENTER机器指令调用内核(并负责使用内核约定传递系统调用号及其参数,这不是通常的C ABI)。内核认为是系统调用的是该机器指令(和约定关于它)。

  2. 处理失败案例,将其传递给errno(3)并返回-1 (IIRC,失败时,进位器或者当内核从SYSENTER返回时,溢出标志位可能会被置位;但我的细节可能是错的)

    < / LI>
  3. 通过返回结果来处理成功案例。

  4. 您可以使用一些汇编程序代码调用不带libc的系统调用。这是不寻常的,但已经完成(例如在BusyBoxBones中)。

    因此libc的{​​{1}}代码正在做一些额外的工作(传递参数,处理失败&amp; write和成功案例)。

    一些系统调用(可能是errno&amp; getpid)避免了clock_gettime机器指令(以及用户模式 ​​- &gt;内核模式切换)的开销,这要归功于{ {3}}

答案 1 :(得分:1)

不,你不能对这样的事情进行分类。当你用C语言编程时(但几乎所有其他语言都没有区别),只有函数,无论这些函数的实际状态是什么,你都可以用完全相同的方式调用它们。这由ABI(如何传递参数,获取返回值等)定义并由编译器/链接器强制执行。当然,一些功能只是存根。例如,存根到共享库函数(存根可能需要加载库,动态链接到实际函数等)或系统调用(这更具技术性,因内核而异)。但是从你的程序的角度看,一切都是一样的(这就是为什么在开始时很难理解freadread之间的区别:你用同样的方式称它们,它们几乎完全相同的工作,有什么区别?)。

POSIX并没有说出关于内核的单一内容......它只是用最少的语义(加上一些命令,工具等)列出了一组函数的C(和以前的ADA)API。这些的实施完全免费。