书籍详情
庖丁解牛Linux操作系统分析
作者:孟宁 娄嘉鹏
出版社:人民邮电出版社
出版时间:2023-08-01
ISBN:9787115619730
定价:¥99.80
购买这本书可以去
内容简介
本书将可移植操作系统 POSIX 标准和 CPU 指令集架构 ISA 两层接口通过 Linux 操作系统贯通起来,涵盖了 Linux 操作系统的各个主要方面,主要有以 openEuler 操作系统为例的 POSIX 工具集、计算机系统的工作原理、x86 和 ARM64 汇编语言、系统调用的工作机制、进程描述和内存管理、可执行程序工作原理、内核线程和 I/O 驱动框架、进程调度和进程切换、KVM 和容器技术、Linux 安全相关技术等 Linux 系统运作的各个关键机制。本书首先以 Linux 社区规则、Linux 发展的渊源、Linux 基本使用和命令工具作为导引;然后以存储程序计算机相关的工作原理、x86 和 ARM64 汇编语言、指令乱序问题、mykernel 精简内核实验以及 Linux内核源代码编译和系统构建作为 Linux 内核的入门基础;接着焦深入理解系统调用,并在 x86 和 ARM64系统调用实现的基础上延伸到进程的创建、可执行程序的加载和进程的切换,其中涉及了进程描述符、进程地址空间和程序编译构建等相关的内容;最后总结了 Linux 系统的一般执行过程和系统架构,并拓展到KVM 和容器技术,以及 Linux 系统安全相关技术。
作者简介
孟宁,任职于中国科学技术大学软件学院,梦宁软件创始人,多年来专注于自主可控基础系统软件研发和教学。曾荣获华为欧拉&高斯开源贡献领英教师奖。著作有《代码中的软件工程》和《庖丁解牛Linux操作系统分析》等图书。主讲课程“软件工程”“Linux操作系统分析”等,曾获评“国家精品在线开放课程”和“国家一流本科课程”,被中国高校计算机教育MOOC联盟评为优秀课程,荣获华为“智能基座”优秀教学资源奖、安徽省教学成果奖二等奖等奖项。娄嘉鹏,高校教师,研究方向包括Linux内核及安全、密码系统设计与实现、软件工程等。曾承担国家863计划、国家科技专项课题多项,荣获省部级科技进步奖一等奖、三等奖多项,拥有多项发明专利和软件著作权。曾荣获“北京市优秀教师”称号,多次被北京蓝墨大数据技术研究院授予“北京市十大魅力教师”荣誉称号。主讲Java程序设计、Linux内核原理与分析、网络攻防实战、密码系统设计等课程。
目录
第 1 章 Linux 操作系统概览 1
1.1 自由软件江湖里的“码头”和规矩 1
1.1.1 自由软件世界的“擎天大柱”Linux 1
1.1.2 江湖的由来——自由软件运动 1
1.1.3 江湖的规矩——开源软件许可证 2
1.1.4 江湖的危局——GPLv2 和 GPLv3 3
1.2 操作系统成长记 4
1.2.1 操作系统诞生的背景 4
1.2.2 早期的软件操作系统 5
1.2.3 系统调用的概念 6
1.2.4 多道程序操作系统 6
1.2.5 笼罩在 UNIX 上的阴影 7
1.2.6 早期个人计算机操作系统的大倒退 7
1.2.7 移动互联网和 AIoT 时代的操作系统 8
1.3 国产操作系统概述... 9
1.3.1 国产操作系统的发展历程 9
1.3.2 openEuler 操作系统 10
1.4 与 Linux 的第 一次亲密接触 13
1.4.1 Linux 内核发展简史 13
1.4.2 安装一个 Linux 系统 14
1.4.3 Linux 命令行简明指南 17
1.5 openEuler 操作系统中的常用 Linux 命令参考 19
1.5.1 查看系统相关信息的命令 19
1.5.2 用户管理和权限管理相关的命令 20
1.5.3 文件和目录相关的命令 21
1.5.4 进程相关的命令 23
1.5.5 进程间通信(IPC)相关的命令 24
1.5.6 基本的开发者工具 24
1.5.7 I/O 相关的命令 25
1.5.8 Shell 脚本中的常用命令 25
本章实验 26
第 2 章 计算机系统的基本工作原理 27
2.1 存储程序计算机 27
2.1.1 哈佛结构与冯·诺依曼结构 27
2.1.2 复杂指令集和精简指令集 29
2.1.3 深入理解冯·诺依曼体系结构 30
2.1.4 计算机的存储系统 32
2.1.5 计算机的总线结构 33
2.2 x86 汇编语言基础 35
2.2.1 x86 CPU 的寄存器 35
2.2.2 基本汇编语言语法规则 39
2.2.3 汇编语言代码片段分析 43
2.2.4 分析完整的 x86 汇编程序 45
2.2.5 函数调用堆栈框架 53
2.2.6 C 语言代码中内嵌汇编语言代码 55
2.3 ARM64 汇编语言基础 58
2.3.1 ARM64 CPU 的寄存器 58
2.3.2 常用的 ARM64 汇编指令 60
2.3.3 分析完整的 ARM64 汇编程序 62
2.4 指令乱序问题65
2.4.1 可重入函数与线程安全 65
2.4.2 编译器指令乱序问题 69
2.4.3 CPU 指令乱序问题 72
2.5 编写一个精简的操作系统内核 75
2.5.1 虚拟一个 64 位 x86 的硬件平台 75
2.5.2 精简的操作系统内核范例代码 76
2.5.3 精简的操作系统内核关键代码分析 80
本章实验 87
第 3 章 Linux 内核源代码及调试环境 90
3.1 Linux 内核源代码.. 90
3.1.1 Linux 内核源代码概述 90
3.1.2 用 VS Code 阅读 Linux 内核源代码 93
3.2 搭建 Linux 内核调试环境 96
3.2.1 编译配置安装 Linux 内核的步骤 96
3.2.2 下载编译内核 97
3.2.3 制作内存根文件系统 98
3.2.4 跟踪调试 Linux 内核的基本方法 99
3.2.5 配置 VS Code 调试 Linux 内核 101
3.3 跟踪 Linux 内核的启动过程103
3.3.1 Linux 内核的启动过程概述 103
3.3.2 跟踪分析 start_kernel 函数 105
本章实验 111
第 4 章 深入理解系统调用 112
4.1 系统调用概述112
4.1.1 用户态、内核态和中断 112
4.1.2 系统调用的基本工作原理 115
4.1.3 x86 Linux 系统调用概述
4.1.4 ARM64 Linux 系统调用概述 118
4.2 触发系统调用的方法 119
4.2.1 使用 C 语言库函数 API 触发系统调用 119
4.2.2 触发系统调用的 32 位 x86 汇编语言代码 121
4.2.3 触发系统调用的 64 位 x86 汇编语言代码 122
4.2.4 触发系统调用的 ARM64 汇编语言代码 123
4.3 深入理解 x86 Linux 系统调用 124
4.3.1 x86 Linux 系统调用的初始化 124
4.3.2 x86 Linux 系统调用的执行 127
4.3.3 x86 Linux 系统调用内核处理函数 132
4.3.4 x86 Linux 系统调用的内核堆栈 135
4.3.5 系统调用中的进程调度时机 137
4.4 深入理解 ARM64 Linux 系统调用 139
4.4.1 ARM64 Linux 异常向量表的初始化 139
4.4.2 ARM64 Linux 系统调用的执行 144
4.4.3 ARM64 Linux 系统调用内核处理函数 149
本章实验 153
第 5 章 进程的描述和创建 154
5.1 进程的描述 154
5.1.1 Linux 进程描述符概览 154
5.1.2 Linux 进程的状态 156
5.1.3 Linux 进程链表结构及父子、兄弟关系 158
5.1.4 Linux 进程关键上下文 159
5.2 进程地址空间163
5.2.1 Linux 内存管理概述 163
5.2.2 Linux 进程地址空间 165
5.2.3 大页内存 169
5.3 进程的创建 172
5.3.1 Linux 内核中进程的初始化 172
5.3.2 用户态创建进程的方法 177
5.3.3 fork 系统调用 179
5.3.4 Linux 内核中进程创建过程 182
5.3.5 进程创建过程中 x86 相关代码 190
5.3.6 进程创建过程中 ARM64 相关代码 193
本章实验 197
第 6 章 可执行程序工作原理 198
6.1 ELF 目标文件格式 198
6.1.1 ELF 目标文件格式概述 198
6.1.2 ELF 文件格式 199
6.1.3 ELF 相关操作命令 203
6.2 程序的编译过程 204
6.2.1 预处理 204
6.2.2 编译 205
6.2.3 汇编 206
6.2.4 链接208
6.3 链接与库 208
6.3.1 符号与符号解析 209
6.3.2 重定位 212
6.3.3 静态链接与动态链接 213
6.3.4 加载时动态链接 214
6.3.5 运行时动态链接 215
6.3.6 动态链接实验 216
6.4 可执行程序的加载 218
6.4.1 程序加载概要 218
6.4.2 execve 与 fork 的区别和联系 222
6.4.3 execve 系统调用的内核处理过程 223
6.4.4 start_thread 函数 229
6.5 系统调用、fork 和 execve 总结 231
本章实验 233
第 7 章 中断处理、内核线程和设备驱动 234
7.1 中断处理概述 234
7.1.1 中断的类型 234
7.1.2 中断处理程序和下半部 235
7.1.3 软中断 239
7.2 内核线程概述 242
7.2.1 内核线程的概念 242
7.2.2 内核线程的创建管理 244
7.3 设备驱动程序 248
7.3.1 一切皆是文件 248
7.3.2 设备的定位和访问 250
7.3.3 设备驱动程序代码结构示例 252
本章实验 254
第 8 章 进程调度与进程切换 255
8.1 进程调度概述 255
8.1.1 进程的分类 255
8.1.2 Linux 进程调度策略 256
8.1.3 CFS 进程调度算法 258
8.2 进程调度的时机... 261
8.3 进程上下文切换... 263
8.3.1 进程执行环境的切换 263
8.3.2 32 位 x86 架构下进程切换核心代码分析 265
8.3.3 64 位 x86 架构下进程切换核心代码分析 269
8.3.4 64 位 x86 架构下 fork 和 execve 相关的进程切换 272
8.3.5 ARM64 架构下进程切换核心代码分析 274
本章实验282
第 9 章 Linux 操作系统的软件架构 283
9.1 Linux 操作系统的一般执行过程 283
9.1.1 32 位 x86 Linux 系统的一般执行过程 283
9.1.2 64 位 x86 Linux 系统的一般执行过程 284
9.1.3 ARM64 Linux 系统的一般执行过程 285
9.1.4 Linux 系统执行过程中的 5 种特殊情况 286
9.2 Linux 操作系统的软件架构分析 287
9.2.1 Linux 操作系统的层次架构 287
9.2.2 Linux 操作系统的地址空间结构 288
9.2.3 Linux 操作系统的执行路径 289
本章实验 290
第 10 章 KVM 及虚拟机技术 291
10.1 虚拟机技术概述. 291
10.1.1 CPU 的虚拟化 292
10.1.2 内存的虚拟化 293
10.1.3 I/O 的虚拟化 294
10.2 KVM API 的使用方法 294
10.2.1 开启或使能 KVM 硬件辅助虚拟化 294
10.2.2 安装配置 KVM 297
10.2.3 使用 KVM API 创建一个虚拟机 297
10.2.4 KVM API 总结 300
10.3 QEMU-KVM 的实现原理 300
10.4 StratoVirt 302
10.4.1 StratoVirt 简介 302
10.4.2 StratoVirt 和 QEMU 的区别 304
10.4.3 StratoVirt 的编译构建 305
10.4.4 StratoVirt 的使用方法 306
本章实验 308
第 11 章 Linux 容器技术.. 309
11.1 容器技术概述 309
11.2 Linux 容器技术的基本原理 311
11.2.1 chroot 技术 311
11.2.2 namespace 技术 315
11.2.3 Mount namespace 316
11.2.4 PID namespace 319
11.2.5 IPC namespace 320
11.2.6 UTS namespace 323
11.2.7 Network namespace 324
11.2.8 User namespace 325
11.2.9 cgroups 技术 326
11.3 如何创建一个容器 331
11.3.1 创建 namespace 的相关系统调用 331
11.3.2 制作 OCI 包并运行容器 332
11.4 Docker 334
11.4.1 Docker 技术概述 334
11.4.2 Dockerfile 和 Docker 镜像 336
11.5 iSula 338
11.5.1 iSula 技术概述 338
11.5.2 iSula 的基本用法 339
11.5.3 iSulad 的系统架构 340
本章实验353
第 12 章 Linux 系统安全相关技术 354
12.1 操作系统安全概述 354
12.1.1 信息安全的设计原则 354
12.1.2 操作系统安全的设计目标 356
12.2 Linux 系统的安全机制 359
12.2.1 Linux 系统的用户账号 359
12.2.2 Linux 文件系统的权限 360
12.2.3 Linux 的日志文件 363
12.2.4 Linux 纵深防御体系 364
12.3 Linux 系统的访问控制 367
12.3.1 Linux 系统访问控制概述 367
12.3.2 Linux Capabilities 374
12.3.3 AppArmor 377
12.3.4 SELinux 379
12.4 可信计算和机密计算 382
12.4.1 secGear 机密计算框架 382
12.4.2 secGear 开发指南 384
本章实验 394
1.1 自由软件江湖里的“码头”和规矩 1
1.1.1 自由软件世界的“擎天大柱”Linux 1
1.1.2 江湖的由来——自由软件运动 1
1.1.3 江湖的规矩——开源软件许可证 2
1.1.4 江湖的危局——GPLv2 和 GPLv3 3
1.2 操作系统成长记 4
1.2.1 操作系统诞生的背景 4
1.2.2 早期的软件操作系统 5
1.2.3 系统调用的概念 6
1.2.4 多道程序操作系统 6
1.2.5 笼罩在 UNIX 上的阴影 7
1.2.6 早期个人计算机操作系统的大倒退 7
1.2.7 移动互联网和 AIoT 时代的操作系统 8
1.3 国产操作系统概述... 9
1.3.1 国产操作系统的发展历程 9
1.3.2 openEuler 操作系统 10
1.4 与 Linux 的第 一次亲密接触 13
1.4.1 Linux 内核发展简史 13
1.4.2 安装一个 Linux 系统 14
1.4.3 Linux 命令行简明指南 17
1.5 openEuler 操作系统中的常用 Linux 命令参考 19
1.5.1 查看系统相关信息的命令 19
1.5.2 用户管理和权限管理相关的命令 20
1.5.3 文件和目录相关的命令 21
1.5.4 进程相关的命令 23
1.5.5 进程间通信(IPC)相关的命令 24
1.5.6 基本的开发者工具 24
1.5.7 I/O 相关的命令 25
1.5.8 Shell 脚本中的常用命令 25
本章实验 26
第 2 章 计算机系统的基本工作原理 27
2.1 存储程序计算机 27
2.1.1 哈佛结构与冯·诺依曼结构 27
2.1.2 复杂指令集和精简指令集 29
2.1.3 深入理解冯·诺依曼体系结构 30
2.1.4 计算机的存储系统 32
2.1.5 计算机的总线结构 33
2.2 x86 汇编语言基础 35
2.2.1 x86 CPU 的寄存器 35
2.2.2 基本汇编语言语法规则 39
2.2.3 汇编语言代码片段分析 43
2.2.4 分析完整的 x86 汇编程序 45
2.2.5 函数调用堆栈框架 53
2.2.6 C 语言代码中内嵌汇编语言代码 55
2.3 ARM64 汇编语言基础 58
2.3.1 ARM64 CPU 的寄存器 58
2.3.2 常用的 ARM64 汇编指令 60
2.3.3 分析完整的 ARM64 汇编程序 62
2.4 指令乱序问题65
2.4.1 可重入函数与线程安全 65
2.4.2 编译器指令乱序问题 69
2.4.3 CPU 指令乱序问题 72
2.5 编写一个精简的操作系统内核 75
2.5.1 虚拟一个 64 位 x86 的硬件平台 75
2.5.2 精简的操作系统内核范例代码 76
2.5.3 精简的操作系统内核关键代码分析 80
本章实验 87
第 3 章 Linux 内核源代码及调试环境 90
3.1 Linux 内核源代码.. 90
3.1.1 Linux 内核源代码概述 90
3.1.2 用 VS Code 阅读 Linux 内核源代码 93
3.2 搭建 Linux 内核调试环境 96
3.2.1 编译配置安装 Linux 内核的步骤 96
3.2.2 下载编译内核 97
3.2.3 制作内存根文件系统 98
3.2.4 跟踪调试 Linux 内核的基本方法 99
3.2.5 配置 VS Code 调试 Linux 内核 101
3.3 跟踪 Linux 内核的启动过程103
3.3.1 Linux 内核的启动过程概述 103
3.3.2 跟踪分析 start_kernel 函数 105
本章实验 111
第 4 章 深入理解系统调用 112
4.1 系统调用概述112
4.1.1 用户态、内核态和中断 112
4.1.2 系统调用的基本工作原理 115
4.1.3 x86 Linux 系统调用概述
4.1.4 ARM64 Linux 系统调用概述 118
4.2 触发系统调用的方法 119
4.2.1 使用 C 语言库函数 API 触发系统调用 119
4.2.2 触发系统调用的 32 位 x86 汇编语言代码 121
4.2.3 触发系统调用的 64 位 x86 汇编语言代码 122
4.2.4 触发系统调用的 ARM64 汇编语言代码 123
4.3 深入理解 x86 Linux 系统调用 124
4.3.1 x86 Linux 系统调用的初始化 124
4.3.2 x86 Linux 系统调用的执行 127
4.3.3 x86 Linux 系统调用内核处理函数 132
4.3.4 x86 Linux 系统调用的内核堆栈 135
4.3.5 系统调用中的进程调度时机 137
4.4 深入理解 ARM64 Linux 系统调用 139
4.4.1 ARM64 Linux 异常向量表的初始化 139
4.4.2 ARM64 Linux 系统调用的执行 144
4.4.3 ARM64 Linux 系统调用内核处理函数 149
本章实验 153
第 5 章 进程的描述和创建 154
5.1 进程的描述 154
5.1.1 Linux 进程描述符概览 154
5.1.2 Linux 进程的状态 156
5.1.3 Linux 进程链表结构及父子、兄弟关系 158
5.1.4 Linux 进程关键上下文 159
5.2 进程地址空间163
5.2.1 Linux 内存管理概述 163
5.2.2 Linux 进程地址空间 165
5.2.3 大页内存 169
5.3 进程的创建 172
5.3.1 Linux 内核中进程的初始化 172
5.3.2 用户态创建进程的方法 177
5.3.3 fork 系统调用 179
5.3.4 Linux 内核中进程创建过程 182
5.3.5 进程创建过程中 x86 相关代码 190
5.3.6 进程创建过程中 ARM64 相关代码 193
本章实验 197
第 6 章 可执行程序工作原理 198
6.1 ELF 目标文件格式 198
6.1.1 ELF 目标文件格式概述 198
6.1.2 ELF 文件格式 199
6.1.3 ELF 相关操作命令 203
6.2 程序的编译过程 204
6.2.1 预处理 204
6.2.2 编译 205
6.2.3 汇编 206
6.2.4 链接208
6.3 链接与库 208
6.3.1 符号与符号解析 209
6.3.2 重定位 212
6.3.3 静态链接与动态链接 213
6.3.4 加载时动态链接 214
6.3.5 运行时动态链接 215
6.3.6 动态链接实验 216
6.4 可执行程序的加载 218
6.4.1 程序加载概要 218
6.4.2 execve 与 fork 的区别和联系 222
6.4.3 execve 系统调用的内核处理过程 223
6.4.4 start_thread 函数 229
6.5 系统调用、fork 和 execve 总结 231
本章实验 233
第 7 章 中断处理、内核线程和设备驱动 234
7.1 中断处理概述 234
7.1.1 中断的类型 234
7.1.2 中断处理程序和下半部 235
7.1.3 软中断 239
7.2 内核线程概述 242
7.2.1 内核线程的概念 242
7.2.2 内核线程的创建管理 244
7.3 设备驱动程序 248
7.3.1 一切皆是文件 248
7.3.2 设备的定位和访问 250
7.3.3 设备驱动程序代码结构示例 252
本章实验 254
第 8 章 进程调度与进程切换 255
8.1 进程调度概述 255
8.1.1 进程的分类 255
8.1.2 Linux 进程调度策略 256
8.1.3 CFS 进程调度算法 258
8.2 进程调度的时机... 261
8.3 进程上下文切换... 263
8.3.1 进程执行环境的切换 263
8.3.2 32 位 x86 架构下进程切换核心代码分析 265
8.3.3 64 位 x86 架构下进程切换核心代码分析 269
8.3.4 64 位 x86 架构下 fork 和 execve 相关的进程切换 272
8.3.5 ARM64 架构下进程切换核心代码分析 274
本章实验282
第 9 章 Linux 操作系统的软件架构 283
9.1 Linux 操作系统的一般执行过程 283
9.1.1 32 位 x86 Linux 系统的一般执行过程 283
9.1.2 64 位 x86 Linux 系统的一般执行过程 284
9.1.3 ARM64 Linux 系统的一般执行过程 285
9.1.4 Linux 系统执行过程中的 5 种特殊情况 286
9.2 Linux 操作系统的软件架构分析 287
9.2.1 Linux 操作系统的层次架构 287
9.2.2 Linux 操作系统的地址空间结构 288
9.2.3 Linux 操作系统的执行路径 289
本章实验 290
第 10 章 KVM 及虚拟机技术 291
10.1 虚拟机技术概述. 291
10.1.1 CPU 的虚拟化 292
10.1.2 内存的虚拟化 293
10.1.3 I/O 的虚拟化 294
10.2 KVM API 的使用方法 294
10.2.1 开启或使能 KVM 硬件辅助虚拟化 294
10.2.2 安装配置 KVM 297
10.2.3 使用 KVM API 创建一个虚拟机 297
10.2.4 KVM API 总结 300
10.3 QEMU-KVM 的实现原理 300
10.4 StratoVirt 302
10.4.1 StratoVirt 简介 302
10.4.2 StratoVirt 和 QEMU 的区别 304
10.4.3 StratoVirt 的编译构建 305
10.4.4 StratoVirt 的使用方法 306
本章实验 308
第 11 章 Linux 容器技术.. 309
11.1 容器技术概述 309
11.2 Linux 容器技术的基本原理 311
11.2.1 chroot 技术 311
11.2.2 namespace 技术 315
11.2.3 Mount namespace 316
11.2.4 PID namespace 319
11.2.5 IPC namespace 320
11.2.6 UTS namespace 323
11.2.7 Network namespace 324
11.2.8 User namespace 325
11.2.9 cgroups 技术 326
11.3 如何创建一个容器 331
11.3.1 创建 namespace 的相关系统调用 331
11.3.2 制作 OCI 包并运行容器 332
11.4 Docker 334
11.4.1 Docker 技术概述 334
11.4.2 Dockerfile 和 Docker 镜像 336
11.5 iSula 338
11.5.1 iSula 技术概述 338
11.5.2 iSula 的基本用法 339
11.5.3 iSulad 的系统架构 340
本章实验353
第 12 章 Linux 系统安全相关技术 354
12.1 操作系统安全概述 354
12.1.1 信息安全的设计原则 354
12.1.2 操作系统安全的设计目标 356
12.2 Linux 系统的安全机制 359
12.2.1 Linux 系统的用户账号 359
12.2.2 Linux 文件系统的权限 360
12.2.3 Linux 的日志文件 363
12.2.4 Linux 纵深防御体系 364
12.3 Linux 系统的访问控制 367
12.3.1 Linux 系统访问控制概述 367
12.3.2 Linux Capabilities 374
12.3.3 AppArmor 377
12.3.4 SELinux 379
12.4 可信计算和机密计算 382
12.4.1 secGear 机密计算框架 382
12.4.2 secGear 开发指南 384
本章实验 394
猜您喜欢