在我上次的工作面试中,我被问到了一个看似非常直接简单的问题:
问: 哪个库系统调用(是内核空间而不是libc中的包装器)是在哪个库中实现的?
答:我回答了
面试官告诉我这是错误的,他问的是它在哪个库中实现,而不是在哪个头文件中声明。
为什么我的答案是错误的,正确答案是什么?
我在网上搜索了几个小时,但什么也没找到,甚至在 shell 中写
man 2 syscall
也会给出:
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
long syscall(long number, ...);
syscall
是一个包装器,实际加载寄存器并在 64 位 x86 上执行指令 syscall
或在 32 位 x86 上执行 int 80h
或 sysenter
,它是标准库的一部分。
示例:
syscall:
endbr64
mov rax,rdi
mov rdi,rsi
mov rsi,rdx
mov rdx,rcx
mov r10,r8
mov r8,r9
mov r9,QWORD PTR [rsp+0x8]
syscall
所以答案是
syscall
函数在 glibc 中。
在内核的汇编文件中,syscall、sysentry 指令条目或 int 80h 中断处理程序(取决于系统实现)会执行一些堆栈魔术,执行一些检查,然后调用将处理特定
system call
的函数。这些函数的地址被放置在包含函数指针的特殊表中。但这部分很难称为“图书馆”。
棘手的问题——(linux)内核中没有“库”。 简短回答:“syscall.c”,通常位于内核源代码树中的“/arch/{arch_name}/syscall.c”
头文件的形式为 *.h,可以添加到 C 程序源代码中。它们通常位于类 Unix 操作系统上的 /usr/include 目录中。标准库头文件通常实际上并不提供人们在包含它们时可能假设的所需函数,而是提供预处理宏,而如果需要库中的函数,它们还提供外部链接,允许您最终使用隐藏的那些库其他地方。
与源代码中包含的头文件不同,库可以包含一些不同的想法,但通常会使用编译器的选项和标志进行链接或作为参数传递给它。库通常存档在 /usr/lib 中,或者由系统开发人员作为共享对象分发。通过研究一些链接器工具,您应该能够找到您正在搜索的内容。