man 2 的系统调用是如何被调用的?

man 2 的系统调用是如何被调用的?

我所说的系统调用是指诸如 之类的函数man 2 brk,而不是0x80中断。

如果我明白的话这个线程正确的是,编译后的 C 程序永远不会直接地调用系统调用。它只能调用库调用,这些调用可能是从glibc.

然而,man 3 brk回报No manual entry for brk in section 3。所以我想必须发生以下情况之一才能brk正确执行:

  1. 我上面的理解是错误的。程序无需支持即可调用系统调用glibc。但如何brk链接到程序中呢?
  2. 确实有一个glibc系统调用的包装器brk。那么brk我的时候包含哪些呢#include <unistd.h>?是一个glibc还是系统调用一个?如果是glibc这样,为什么没有记录在案man 3?在哪里可以找到可用库调用的完整列表?

答案1

对于第 2 节中的手册页中的大多数系统调用,手册页实际上描述了 C 库包装器。通常会明确提及例外情况,例如gettid@Sergei Kurenkov 在他们的回答中提到:

笔记Glibc 不提供此系统调用的包装器;使用 syscall(2) 调用它。

pivot_root与(对于一般应用程序没有多大用处)类似, tgkill(执行 的低级功能pthread_kill)。然后还有readdir,其中实际的系统调用与库函数有些不同:

描述这不是您感兴趣的函数。请查看 readdir(3) 以了解符合 POSIX 的 C 库接口。本页记录了裸内核系统调用接口,该接口已被 getdents(2) 取代。

请注意,必须有某种包装器。函数调用是使用 C 调用约定进行的,这与内核接口的调用约定不同。通常的函数调用是使用call汇编指令(或类似指令)进行的,内核调用是使用syscallor int 0x80(这不包括gettimeofdaygetpid中的内容vdso)。编译器不(不需要)知道哪些函数调用映射到实际的内核调用。

即使使用“通常的”系统调用,C 库包装器的行为也与裸系统调用略有不同:系统调用将错误代码返回为不同的负值(如果您查看 Linux 内核代码,您会看到很多返回类似return -EPERM;)。 C 库包装器将所有此类返回值转换为 -1,并将实际错误代码移至errno

答案2

编译后的 C 程序从不直接调用系统调用。

这不是真的。以agettid为例:http://man7.org/linux/man-pages/man2/gettid.2.html。它没有包装器,因此您需要在程序中编写类似的内容(来自 man: Glibc does not provide a wrapper for this system call; call it using syscall(2).):

#ifndef WIN32

#include <linux/unistd.h>
#include <sys/syscall.h>
#include <unistd.h>
int thread_gettid(void) {
    return static_cast<int>(syscall(SYS_gettid));
}
#else
int thread_gettid(void) {
    return GetCurrentThreadId();
}
#endif

我上面的理解是错误的。程序可以在没有 glibc 支持的情况下调用系统调用。

确实可以。它用syscallhttp://man7.org/linux/man-pages/man2/syscall.2.html

那么brk是如何链接到程序中的呢?

看来brkglibc 确实有一个包装器,因为 man 中有这一行:

The return value described above for brk() is the behavior provided 
by the glibc wrapper function for the Linux brk() system call.

如果是 glibc 的话,为什么 man 3 中没有记录呢

我认为这是因为必须malloc使用内存分配:

避免使用 brk() 和 sbrk():malloc(3) 内存分配包是可移植且舒适的内存分配方式。

相关内容