这本书主要是用讲故事的方式介绍计算机底层相关的技术,用通俗易懂的表达方式帮助大家学习底层技术。
故事的主人公可能是计算机里的一个程序、一个进程、一个线程、一个函数、一个数据包、一个文件等这样的软件角色,也可能是CPU、内存、网卡等这样的硬件角色。
本书透过这些角色的视角去讲述发生在计算机世界里的故事,帮助大家在故事中学习和了解计算机底层技术的工作原理。
整本书由几十个故事构成,故事之间既有关联性,让你像“追剧”一样学习技术,也有一定的独立性,让你随时翻开一篇都能看下去。
本书主要涵盖计算机中的CPU、存储、I/O、操作系统、系统编程、安全六个主题,每个主题一章,你不必从头到尾逐篇阅读,完全可以挑选自己感兴趣的任何章节开始阅读。
第1章 计算机的大脑:中央处理器CPU
1.1 CPU的细胞:门电路
1.1.1 逻辑门
1.1.2 加法器
1.1.3 算术逻辑单元ALU
1.2 程序的本质:指令
1.2.1 指令集
1.2.2 寄存器
1.2.3 汇编语言
1.2.4 高级语言
1.2.5 指令执行过程
1.3 像流水线一样执行指令
1.3.1 指令流水线
1.3.2 流水线的级数
1.3.3 流水线里的冒险
1.4 CPU里的存储设施:缓存
1.4.1 缓存
1.4.2 缓存行
1.4.3 指令缓存与数据缓存
1.5 多核缓存不一致引发的问题
1.5.1 原子操作
1.5.2 缓存引发的问题
1.5.3 缓存一致性协议MESI
1.6 指令还能乱序执行
1.6.1 数据冒险与流水线停顿
1.6.2 乱序执行
1.7 跳还是不跳,这是一个问题
1.7.1 静态预测
1.7.2 动态预测
1.8 一条指令同时处理多个数据
1.8.1 一个简单的循环
1.8.2 并行计算
1.8.3 一条指令处理多个数据
1.9 一个核同时执行两个线程
1.9.1 资源闲置
1.9.2 超线程技术
1.10 CPU是如何管理内存的
1.10.1 8086
1.10.2 32位时代
1.10.3 虚拟内存
1.10.4 分页交换
1.11 CPU地址翻译的备忘录
1.11.1 虚拟地址翻译
1.11.2 地址翻译缓存
1.11.3 翻译后备缓冲区
1.12 GPU和CPU有什么区别
1.12.1 庞大的核心数量
1.12.2 GPU的SIMT与“超线程”
第2章 计算机中的存储设施
2.1 缓存为什么比内存还快
2.2 内存条是如何存储数据的
2.2.1 数据存储
2.2.2 内存编址
2.3 多个CPU如何共同访问内存
2.3.1 NUMA架构
2.3.2 操作系统支持
2.3.3 内存分配问题
2.4 机械硬盘存储数据的原理
2.5 硬盘那么大,计算机如何管理
2.5.1 扇区和块
2.5.2 块位图
2.5.3 inode
2.5.4 目录
2.5.5 块组、组描述符、超级块
2.5.6 引导块、分区DBR和MBR
第3章 数据的输入与输出
3.1 计算机中的高速公路
3.1.1 早期的总线系统
3.1.2 南桥与北桥
3.1.3 消失的北桥
3.2 其他设备如何与CPU通信
3.2.1 8259A可编程中断控制器
3.2.2 APIC高级可编程中断控制器
3.2.3 中断亲和性
3.3 计算机启动的过程
3.3.1 开始执行
3.3.2 MBR
3.3.3 操作系统
3.4 CPU把数据搬运的工作“外包”出去
3.4.1 PIO模式
3.4.2 DMA技术
3.4.3 DMA全面开花
3.5 神奇的零拷贝技术
3.5.1 数据的四次拷贝
3.5.2 零拷贝技术
3.6 网卡是如何工作的
3.6.1 集线器时代
3.6.2 数据收发过程
3.6.3 交换机时代
3.7 网卡收到数据包后发生什么
3.7.1 数据帧校验
3.7.2 DMA数据传输
3.7.3 软中断
3.7.4 轮询收包
3.7.5 协议栈
3.8 绕过操作系统,直接收发数据包
3.8.1 万兆流量需求
3.8.2 中断问题
3.8.3 超快的抓包技术:DPDK
3.8.4 空转问题
第4章 计算机的大管家:操作系统
4.1 一个控制程序的进化
4.1.1 多道程序处理
4.1.2 时间分片
4.1.3 状态
4.1.4 优先级
4.1.5 多核时代
4.2 程序运行的实体:进程
4.2.1 进程地址空间
4.2.2 进程调度
4.2.3 进程与线程
4.3 CPU的执行流:线程
4.4 内核地址空间历险记:系统调用
4.4.1 神秘的长者
4.4.2 系统调用
4.4.3 内核堆栈
4.5 当除数为0时,CPU发生了什么
4.5.1 中断和异常
4.5.2 信号投递
4.5.3 异常返回
4.6 发给进程的信号,到底去哪儿了
4.6.1 可靠信号与不可靠信号
4.6.2 信号的处理
4.6.3 多线程的信号处理
4.7 困住线程的锁,到底是什么
4.7.1 原子操作
4.7.2 自旋锁
4.7.3 互斥锁
4.7.4 条件变量
4.7.5 信号量
4.8 Linux的权限管理
4.8.1 打开文件的过程
4.8.2 权限检查
4.8.3 UGO与ACL检查
4.8.4 Cgroup与SELinux的检查
4.9 计算机中“楚门的世界”
4.9.1 隐藏文件系统:chroot与pivot_root
4.9.2 进程的隔离:命名空间
4.9.3 行为的限制:Cgroup
第5章 系统编程那些事儿
5.1 进程是如何诞生的
5.1.1 奇怪的fork
5.1.2 写时拷贝
5.1.3 消失的线程们
5.2 线程的栈里都装了什么
5.2.1 自动增长
5.2.2 内核栈
5.2.3 栈溢出
5.3 进程间如何通信
5.3.1 信号
5.3.2 socket套接字
5.3.3 匿名管道
5.3.4 消息队列
5.3.5 共享内存
5.4 高性能基础:I/O多路复用
5.4.1 select模型
5.4.2 poll模型
5.4.3 epoll模型
5.5 像访问内存一样读写文件
5.5.1 传统文件读写
5.5.2 内存映射文件
5.6 线程里的多个执行流:协程
5.6.1 线程阻塞问题
5.6.2 多个执行流的“调度”
5.7 调试器是如何工作的
5.7.1 软件断点
5.7.2 单步调试
5.7.3 内存断点
5.8 可执行文件ELF
5.8.1 格式识别
5.8.2 ELF文件格式
5.8.3 加载过程
第6章 计算机的攻击与安全防护
6.1 TCP序列号的秘密
6.1.1 TCP初始化序列号是多少
6.1.2 Linux协议栈里的计数器
6.2 “猜出”TCP的序列号
6.2.1 神秘的TCP计数器
6.2.2 奇怪的TCP连接
6.2.3 基于计数器的侧信道攻击
6.3 危险的TCP SYN Flood
6.3.1 SYN洪水攻击
6.3.2 安全防护:SYN Cookie
6.4 从HTTP到HTTPS的进化
6.4.1 第一版:直接简单加密
6.4.2 第二版:非对称加密
6.4.3 第三版:非对称与对称加密结合
6.4.4 第四版:密钥计算
6.4.5 第五版:数字证书
6.4.6 第六版:信任链
6.5 线程栈里的秘密行动
6.5.1 栈溢出与Stack Canary
6.5.2 虚函数攻击
6.6 CPU分支预测引发的危机
6.6.1 触发分支预测
6.6.2 乱序执行与缓存引发的攻击
6.6.3 KPTI内核页表隔离
6.7 CPU中隐藏的秘密基地
6.7.1 神秘的SGX
6.7.2 CPU里的禁区
6.7.3 内存加密
6.8 躲在暗处的挖矿病毒
6.9 服务器被挖矿,Redis竟是内鬼
6.9.1 挖矿病毒的入侵
6.9.2 Redis持久化存储“闯祸了”
6.10 整数+1引发的内核攻击
6.10.1 IDT被谁篡改了?
6.10.2 有符号与无符号大有不同
6.10.3 整数+1的悲剧
6.11 从虚拟机中逃脱
6.11.1 虚拟化技术
6.11.2 虚拟机逃逸技术