【发布时间】:2017-10-09 12:36:22
【问题描述】:
我知道系统调用不在 C 标准库中。是否有系统调用所在的库(某种系统库)?
如果有这样的库,这个库是如何链接到可执行程序的?
【问题讨论】:
标签: c linux linux-kernel shared-libraries system-calls
我知道系统调用不在 C 标准库中。是否有系统调用所在的库(某种系统库)?
如果有这样的库,这个库是如何链接到可执行程序的?
【问题讨论】:
标签: c linux linux-kernel shared-libraries system-calls
系统调用可以以几种不同的方式工作,具体取决于目标架构,但无论如何,它不是库调用。这是运行中的用户空间程序调用内核中某些功能的一种方式。
在非常旧的系统中,这通常意味着直接跳转到该内核函数开始的某个地址。后来,内核引入了“跳转表”,增加了一层间接性,因此内核更改时地址不必更改。这种简单的方法在很长一段时间内都不再起作用(Linux 从未使用过它),因为如今,用户空间程序以某种“受保护”模式运行,该模式限制了它们可以做什么并让它们在虚拟地址空间中运行,因此保护系统不会因为一个用户空间程序错误而崩溃。
因此需要新的方法将 CPU 置于允许 任何 代码的模式(特权模式),并确保仅将控制权传递给内核,因此其他代码不会意外地以特权模式运行模式。在x86 上,这通常使用触发软中断的int 指令完成,内核处理该中断。在amd64 上,有一条特殊的syscall 指令用于进入内核。
在任何的情况下,C 不知道系统调用。您不能直接在 C 中发出系统调用(但您可以使用 内联汇编,如果您知道您的目标架构)。 Linux 上的 C 库包含许多函数,它们只是实际系统调用的微小包装,因此您可以直接从 C 中使用它们。
尽管不在问题的范围内:与 Linux 不同,Windows 隐藏系统调用,以至于它们甚至没有记录在案并且随时可能更改。在 Windows 上,您应该仅为您的应用软件使用系统库(如 user32.dll)。
【讨论】:
系统调用(在syscalls(2) 中列出)主要由 linux 内核解释。 C 库只包含与内核接口的胶水代码。从应用程序 (user-land) 的角度来看,系统调用是 atomic,并且几乎是一条 machine code 指令(SYSCALL 或 SYSENTER on x86-64)。用于调用系统调用的ABI 不是C ABI。另见Linux Assembler HowTo 和x86-64 ABI。使用strace(1) 了解某些命令或进程执行了哪些系统调用。
了解operating systems、system calls、linux kernel。
SYSENTER(或SYSCALL)机器指令将CPU mode 从user-mode 切换到内核模式。然后内核在特权[内核]模式下运行许多(数百万)机器指令,最后将执行SYSEXIT(或SYSRETURN)机器指令返回到用户模式。内核甚至可以安排另一个任务。所以从应用程序的角度来看,系统调用是一种基本的虚拟机指令;应用程序代码只是“看到”一个非常复杂的机器指令执行整个系统调用,而这种错觉是由内核提供的。
另请参阅this answer 相关问题。
(您可以通过直接在汇编程序中进行系统调用来避免使用 libc;Bones 是此类程序的一个示例;但几乎所有 Linux 上的程序都使用了一些 libc)。
另请阅读vdso(7)、ld-linux(8)、elf(5)。
【讨论】:
该库是标准 C 库 (libc)。这通常是 glibc,但一些嵌入式 linux 将使用 musl,而 Android 使用仿生。
Linux 作为一个平台是相当独特的,因为内核/用户界面相当稳定,因此可以使用不同的 c 库。
libc 库将被您的工具链作为共享库自动链接,除非您告诉它不要这样做。
【讨论】: