Linux系统调用的最终指南

1.概述

这篇博客解释了Linux程序如何调用Linux内核中的函数。

它将概述几种进行系统调用的不同方法,如何手工制作自己的程序集来进行系统调用(包括示例),系统调用的内核入口点,系统调用的内核出口点,glibc包装器,bug等等。

2.什么是系统调用

当您运行一个调用了open、fork、read、write(以及许多其他)的程序时,您正在进行系统调用。

系统调用是程序进入内核执行某些任务的方式。程序使用系统调用来执行各种操作,例如:创建进程、执行网络和文件IO等等。

通过检索syscalls(2)的手册页,可以找到系统调用的列表。

用户程序有几种不同的方式进行系统调用,而进行系统调用的低级指令在不同的CPU架构中有所不同。

作为一名应用程序开发人员,您通常不需要考虑如何准确地进行系统调用。您只需包含适当的头文件,然后像调用普通函数一样调用它。

glibc提供了包装器代码,它将您从安排传递的参数并进入内核的底层代码中抽象出来。
在深入研究如何进行系统调用之前,我们需要定义一些术语,并检查稍后将出现的一些核心思想。

2.先前准备

2.1 硬件和软件

本文假设:

  • 您使用的是32位或64位Intel或AMD CPU。关于这些方法的讨论可能对使用其他系统的人有用,但是下面的代码示例包含特定于cpu的代码。
  • 您对Linux内核3.13.0版本感兴趣。其他内核版本将是类似的,但是具体的行号、代码组织和文件路径将有所不同。GitHub上有3.13.0内核源代码树。
  • 您对glibc或glibc派生的libc实现(例如,eglibc)感兴趣。

在这篇博文中,x86-64将提到64位Intel和AMD CPU,它们都是基于x86架构的。

2.2 用户程序、内核和CPU特权级别

用户程序(如您的编辑器、终端、ssh守护进程等)需要与Linux内核交互,以便内核能够代表您的用户程序执行一组它们不能自己执行的操作。

例如,如果用户程序需要执行某种IO(打开、读、写等)或修改其地址空间(mmap、sbrk等),它必须触发内核运行,以代表它完成这些操作。

是什么阻止用户程序自己执行这些操作?

事实证明,x86-64 cpu有一个称为特权级别1的概念。特权级别是一个复杂的主题,比较适合使用单独的博客来解释它。就本文而言,我们可以(大大)简化特权级别的概念,方法是:

  1. 特权级别是一种访问控制手段。当前的特权级别决定可以执行哪些CPU指令和IO。
  2. 内核运行在最特权级别,称为“Ring 0”。用户程序在较低的级别上运行,通常是“Ring 3”。

为了让用户程序执行某些特权操作,它必须引起特权级别的更改(从“Ring 3”更改为“Ring 0”),以便内核可以执行。

有多种方法可以引起特权级别的更改,并触发内核执行某些操作。

让我们从一种导致内核执行的常见方法开始:中断。

2.3 中断

您可以将中断看作是由硬件或软件生成(或“引发”)的事件。

硬件设备引发硬件中断,通知内核发生了特定事件。这种类型的中断的一个常见例子是当NIC【Network Interface Card】(即网卡、网络适配器)接收到一个包时产生的中断。

软件中断是通过执行一段代码引发的。在x86-64系统上,可以通过执行int指令引发软件中断。

中断通常有分配给它们的数字。有些中断的数字有特殊的含义。

您可以想象一个驻留在CPU内存中的数组。这个数组中的每个条目映射到一个中断号。每个条目包含一个函数的地址,当接收到这个中断时,CPU将开始执行这个函数,同时还包含一些选项,比如中断处理函数应该在哪个特权级别执行。
这是一张来自Intel CPU手册的图片,展示了这个数组中的一个条目的布局:
在这里插入图片描述


  1. x86指令集中的特权级别控制当前在处理器上运行的程序对资源(如内存区域、I/O端口和特殊指令)的访问。有4个特权级别,从0到3。大多数现代操作系统对内核/执行程序使用0级,对应用程序使用3级。级别n可用的任何资源对级别0到n也是可用的,所以特权级别是环。当较弱的特权进程试图访问较高的特权进程时,操作系统会报告一般的保护错误异常。
    没有必要使用所有四个特权级别。目前市场份额较大的操作系统,包括Microsoft Windows、macOS、Linux、iOS、Android等,大多采用单比特的分页机制,指定权限级别为管理员或用户(U/S比特)。Windows NT使用两级系统。在8086中的实际模式程序在第0级(最高特权级)执行,而在8086中的虚拟模式在第3级执行所有程序。
    x86 ISA家族支持的多个特权级别的潜在未来用途包括容器化和虚拟机。主机操作系统内核可以使用具有完全特权访问的指令(内核模式),而在虚拟机或容器中的来宾操作系统上运行的应用程序可以在用户模式中使用最低级别的特权。虚拟机和客户操作系统内核本身可以使用中级指令特权来调用和虚拟化内核模式操作,例如从客户操作系统的角度进行系统调用 ↩︎

猜你喜欢

转载自blog.csdn.net/qq_31179577/article/details/84504234