mirror of
https://github.com/MintCN/linux-insides-zh.git
synced 2026-02-02 18:18:57 +08:00
fix: link for markdown
This commit is contained in:
@@ -11,7 +11,7 @@ Linux 内核系统调用 第一节
|
||||
什么是系统调用?
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
系统调用就是从用户空间发起的内核服务请求。操作系统内核其实会提供很多服务,比如当程序想要读写文件、监听某个[socket](https://en.wikipedia.org/wiki/Network_socket)端口、删除或创建目录或者程序结束时,都会执行系统调用。换句话说,系统调用其实就是一些由用户空间程序调用去处理某些请求的 [C] (https://en.wikipedia.org/wiki/C_%28programming_language%29) 内核空间函数。
|
||||
系统调用就是从用户空间发起的内核服务请求。操作系统内核其实会提供很多服务,比如当程序想要读写文件、监听某个[socket](https://en.wikipedia.org/wiki/Network_socket)端口、删除或创建目录或者程序结束时,都会执行系统调用。换句话说,系统调用其实就是一些由用户空间程序调用去处理某些请求的 [C](https://en.wikipedia.org/wiki/C_%28programming_language%29) 内核空间函数。
|
||||
|
||||
Linux 内核提供一系列的函数,但这些函数与CPU架构相关。 例如:[x86_64](https://en.wikipedia.org/wiki/X86-64) 提供 [322](https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl) 个系统调用,[x86](https://en.wikipedia.org/wiki/X86) 提供 [358](https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_32.tbl) 个不同的系统调用。
|
||||
系统调用仅仅是一些函数。 我们看一个使用汇编语言编写的简单 `Hello world` 示例:
|
||||
@@ -85,7 +85,7 @@ wrmsrl(MSR_LSTAR, entry_SYSCALL_64);
|
||||
* 参数字符串指针
|
||||
* 数据的大小
|
||||
|
||||
是的,你没有看错,这就是系统调用的参数。正如上文所示, 系统调用仅仅是内核空间的 `C` 函数。示例中第一个系统调用为 write ,在 [fs/read_write.c] (https://github.com/torvalds/linux/blob/master/fs/read_write.c) 源文件中定义如下:
|
||||
是的,你没有看错,这就是系统调用的参数。正如上文所示, 系统调用仅仅是内核空间的 `C` 函数。示例中第一个系统调用为 write ,在 [fs/read_write.c](https://github.com/torvalds/linux/blob/master/fs/read_write.c) 源文件中定义如下:
|
||||
|
||||
```C
|
||||
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
|
||||
@@ -121,7 +121,7 @@ _exit(0) = ?
|
||||
+++ exited with 0 +++
|
||||
```
|
||||
|
||||
`strace` 输出的第一行, [execve](https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl#L68) 系统调用来执行程序,第二、三行为程序中使用的系统调用: `write` 和 `exit`。注意示例中通过通用目的寄存器传递系统调用的参数。寄存器的顺序是指定的,该顺序在- [x86-64 calling conventions] (https://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions)中定义。
|
||||
`strace` 输出的第一行, [execve](https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl#L68) 系统调用来执行程序,第二、三行为程序中使用的系统调用: `write` 和 `exit`。注意示例中通过通用目的寄存器传递系统调用的参数。寄存器的顺序是指定的,该顺序在- [x86-64 calling conventions](https://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions)中定义。
|
||||
`x86_64` 架构的声明在另一个特别的文档中 - [System V Application Binary Interface. PDF](http://www.x86-64.org/documentation/abi.pdf)。通常,函数参数被置于寄存器或者堆栈中。正确的顺序为:
|
||||
|
||||
* `rdi`
|
||||
@@ -330,7 +330,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
|
||||
* `buf` - 写缓冲区
|
||||
* `count` - 写缓冲区大小
|
||||
|
||||
该调用的功能是将用户定义的缓冲中的数据写入指定的设备或文件。注意第二个参数 `buf`, 定义了 `__user` 属性。该属性的主要目的是通过 [sparse](https://en.wikipedia.org/wiki/Sparse) 工具检查 Linux 内核代码。sparse 定义于 [include/linux/compiler.h] (https://github.com/torvalds/linux/blob/master/include/linux/compiler.h) 头文件中,并依赖 Linux 内核中 `__CHECKER__` 的定义。以上全是关于 `sys_write` 系统调用的有用元信息。我们可以看到,它的实现开始于 `f` 结构的定义,`f` 结构包含 `fd` 结构类型,`fd`是 Linux 内核中的文件描述符,也是我们存放 `fdget_pos` 函数调用结果的地方。`fdget_pos` 函数在相同的[源文件](https://github.com/torvalds/linux/blob/master/fs/read_write.c)中定义,其实就是 `__to_fd` 函数的扩展:
|
||||
该调用的功能是将用户定义的缓冲中的数据写入指定的设备或文件。注意第二个参数 `buf`, 定义了 `__user` 属性。该属性的主要目的是通过 [sparse](https://en.wikipedia.org/wiki/Sparse) 工具检查 Linux 内核代码。sparse 定义于 [include/linux/compiler.h](https://github.com/torvalds/linux/blob/master/include/linux/compiler.h) 头文件中,并依赖 Linux 内核中 `__CHECKER__` 的定义。以上全是关于 `sys_write` 系统调用的有用元信息。我们可以看到,它的实现开始于 `f` 结构的定义,`f` 结构包含 `fd` 结构类型,`fd`是 Linux 内核中的文件描述符,也是我们存放 `fdget_pos` 函数调用结果的地方。`fdget_pos` 函数在相同的[源文件](https://github.com/torvalds/linux/blob/master/fs/read_write.c)中定义,其实就是 `__to_fd` 函数的扩展:
|
||||
|
||||
```C
|
||||
static inline struct fd fdget_pos(int fd)
|
||||
|
||||
@@ -11,7 +11,7 @@ vsyscalls 和 vDSO
|
||||
vsyscalls 介绍
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
`vsyscall` 或 `virtual system call` 是第一种也是最古老的一种用于加快系统调用的机制。 `vsyscall` 的工作原则其实十分简单。Linux 内核在用户空间映射一个包含一些变量及一些系统调用的实现的内存页。 对于 [X86_64](https://en.wikipedia.org/wiki/X86-64) 架构可以在 Linux 内核的 [文档] (https://github.com/torvalds/linux/blob/master/Documentation/x86/x86_64/mm.txt) 找到关于这一内存区域的信息:
|
||||
`vsyscall` 或 `virtual system call` 是第一种也是最古老的一种用于加快系统调用的机制。 `vsyscall` 的工作原则其实十分简单。Linux 内核在用户空间映射一个包含一些变量及一些系统调用的实现的内存页。 对于 [X86_64](https://en.wikipedia.org/wiki/X86-64) 架构可以在 Linux 内核的 [文档](https://github.com/torvalds/linux/blob/master/Documentation/x86/x86_64/mm.txt) 找到关于这一内存区域的信息:
|
||||
|
||||
```
|
||||
ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls
|
||||
|
||||
Reference in New Issue
Block a user