Skip to content

Commit 9d1f3d2

Browse files
author
Lysssyo
committed
add new documentation
1 parent b164843 commit 9d1f3d2

1 file changed

Lines changed: 91 additions & 23 deletions

File tree

docs/01-计算机基础/操作系统/指令集、芯片与操作系统的底层协同.md

Lines changed: 91 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,61 @@
11
---
22
date created: 2026-03-17 11:13:32
3-
date modified: 2026-03-18 00:39:33
3+
date modified: 2026-03-18 00:53:39
44
---
55
# 指令集、芯片与操作系统的底层协同
66

77
指令集、物理芯片和操作系统构成了计算机体系结构中最核心的**抽象层级**。它们之间的关系本质上是“协议”、“实现”与“管理者”的关系。
88

99
---
1010

11-
## 1. 宏观架构与核心定义
12-
13-
### 1.1 核心概念
11+
## 1. 核心概念
1412

1513
- **指令集 (ISA, Instruction Set Architecture)**:软件与硬件之间的沟通“协议”。它定义了 CPU 能够执行的基础命令(机器指令)。
16-
- **物理芯片 (CPU)**指令集的**物理载体与执行者**通过晶体管将抽象指令转化为电子脉冲
14+
- **物理芯片 (CPU)****指令集物理载体与执行者**例如,Intel芯片是x86指令集,Apple M 芯片是 ARM 指令集
1715
- **操作系统 (OS)**:硬件的**管理者与协调者**。它通过指令集指挥芯片,并为应用提供安全的运行环境。
1816

19-
### 1.2 抽象层级关系图
2017
```mermaid
2118
graph TD
22-
App["应用程序"] -->|"发起系统调用"| OS["操作系统"]
23-
OS -->|"编译/翻译为机器指令"| ISA["指令集 (ISA)"]
24-
ISA -->|"规范硬件逻辑设计"| Chip["物理芯片 (CPU)"]
25-
26-
subgraph "软件层 (Software)"
27-
App
28-
OS
19+
subgraph "指令集层 (ISA: 抽象的设计图纸)"
20+
X86["x86 / x86-64 指令集 (CISC)"]
21+
ARM["ARM / AArch64 指令集 (RISC)"]
22+
RISCV["RISC-V 指令集 (开源 RISC)"]
2923
end
30-
31-
subgraph "硬件层 (Hardware)"
32-
ISA
33-
Chip
24+
25+
subgraph "物理芯片层 (CPU: 晶体管造出的真实大脑)"
26+
Intel["Intel Core / Xeon 处理器"]
27+
AMD["AMD Ryzen / EPYC 处理器"]
28+
AppleM["Apple M1/M2/M3 处理器"]
29+
Snapdragon["高通 Snapdragon (骁龙)"]
30+
THead["平头哥 玄铁系列芯片"]
3431
end
32+
33+
subgraph "终端应用场景"
34+
PC["传统 Windows PC / 游戏本 / 服务器"]
35+
Mobile["新款 Mac / iPhone / 安卓手机"]
36+
IoT["物联网设备 / 教学开发板"]
37+
end
38+
39+
X86 -->|"授权与实现"| Intel
40+
X86 -->|"授权与实现"| AMD
41+
42+
ARM -->|"购买图纸与深度定制"| AppleM
43+
ARM -->|"购买图纸与深度定制"| Snapdragon
44+
45+
RISCV -->|"免费开源实现"| THead
46+
47+
Intel -.-> PC
48+
AMD -.-> PC
49+
AppleM -.-> Mobile
50+
Snapdragon -.-> Mobile
51+
THead -.-> IoT
3552
```
3653

54+
> [!TIP]
55+
> - **指令集门派:** 目前主流的指令集架构主要分为两大阵营:主打高性能的 **CISC(复杂指令集,以 x86 为代表)**,以及主打高能效的 **RISC(精简指令集,以 ARM 和开源的 RISC-V 为代表)**
56+
> - **物理芯片厂商:** 厂商拿到或买下指令集图纸后,通过自己设计内部的晶体管排布(微架构设计),把这套图纸变成真实的硅片。
57+
> - **操作系统和指令集、芯片没有必然联系,操作系统是一个软件。**
58+
3759
---
3860

3961
## 2. 静态阶段:从代码到机器指令(编译与链接)
@@ -46,7 +68,7 @@ graph TD
4668

4769
1. **预处理 (Preprocessing)**:处理 `#` 指令,代码仍是 C。
4870
2. **编译 (Compilation)**:将 C 翻译为**汇编指令**(.s)。此时逻辑已锁定在特定 ISA。
49-
3. **汇编 (Assembly)**将汇编助记符**一对一**翻译成二进制**机器指令**(.o)。
71+
3. **汇编 (Assembly)****将汇编助记符一对一翻译成二进制机器指令**(.o)。
5072
4. **链接 (Linking)****OS 登场提供“通讯录”**。链接器将 `.o` 文件与系统提供的 **C 标准库 (libc)** 缝合,解决像 `printf``fork` 这种系统级功能的代码归宿。
5173

5274
> [!NOTE] 汇编与机器指令的关系
@@ -90,7 +112,7 @@ graph TD
90112
- **后端的“按需调用”:**
91113
- 当你在自己的一台 x86 电脑(比如普通的 Windows/Linux PC)上安装 GCC 时,系统默认给你安装的是 **“包含 x86 后端的 GCC”**。所以你敲 `gcc` 时,它默认调用 x86 后端,输出 x86 机器码。
92114
- 如果你买了一台树莓派(ARM 架构),在上面 `apt install gcc`,系统给你装的其实是 **“包含 ARM 后端的 GCC”**。虽然命令也是 `gcc`,但它体内的后端已经换人了。
93-
- **交叉编译 (Cross-Compilation) 暴露了真相:** 假设你现在用着 x86 的电脑,但你需要给一台 ARM 架构的智能音箱写 C 程序。这时候你普通的 `gcc` 就罢工了。你必须专门去下载并安装一个名为 `arm-linux-gnueabihf-gcc` 的特定编译器。这就是典型的“在 A 架构上,运行带有 B 架构后端的编译器”。
115+
- **交叉编译 (Cross-Compilation)** 假设你现在用着 x86 的电脑,但你需要给一台 ARM 架构的智能音箱写 C 程序。这时候你普通的 `gcc` 就罢工了。你必须专门去下载并安装一个名为 `arm-linux-gnueabihf-gcc` 的特定编译器。这就是典型的“在 A 架构上,运行带有 B 架构后端的编译器”。
94116

95117
### 2.3 解释型与虚拟机(Java/Python)
96118

@@ -246,15 +268,61 @@ graph LR
246268
> - **位置三:阻隔在程序与芯片之间的“目标 OS”。** 对于 x86 和 ARM 这种通用计算机系统,生成的可执行文件(如 ELF 或 exe)绝对不可能直接扔给物理芯片。它必须先交给目标 OS。目标 OS 负责双击运行、分配虚拟内存、建立页表,最后才由 OS 的调度器把机器指令一条条送进 CPU。
247269
> - **特例对比:RISC-V 裸机分支** 如果你写的是直接跑在单片机或物联网芯片(如简单的 RISC-V 芯片)上的代码,那里**没有操作系统**。此时,链接器会生成一种极其纯粹的二进制文件(如 `.bin``.hex`),通过烧录器**直接强行写入芯片的物理闪存**。开机通电,芯片直接从第一行代码开始执行。只有在这种“Bare Metal(裸机)”环境下,代码才是真正越过 OS,直达物理芯片的。
248270
271+
## 5. 其他问题
272+
273+
操作系统和计算机架构(x86,arm)有什么关系呢?
274+
275+
**操作系统和计算机架构没有必然联系。** 例如 Linux 操作系统可以运行在 x86架构的芯片上,也可以运行在 arm 架构的芯片上。因为,操作系统归根结底也就是一个极其庞大、极其复杂的软件程序。它到底会使用哪种架构,完全取决于你在编译它时,**选择了哪一条“工具链流水线”以及对应的目标芯片。** 相当于图中的 `CODE["C / C++ 源码"]`
276+
249277
> [!TIP]
250278
> 在图里的 `CODE["C / C++ 源码"]` 这个框框里:
251279
>
252280
> - 如果你放进去的是你写的业务代码,编译出来就是跑在系统上的**普通应用程序**
253281
> - 如果你放进去的是 Linus Torvalds 写的 **Linux 内核源码**,编译出来的就是**操作系统本身**
254-
>
255-
> 操作系统归根结底也就是一个极其庞大、极其复杂的软件程序。它到底会使用哪种指令集(方言),完全取决于你在编译它时,**选择了哪一条“工具链流水线”以及对应的目标芯片。**
256282
257-
虽然我们说操作系统可以等同于图中的 C 代码,但物理芯片毕竟存在硬件差异(比如 x86 的特权指令叫 `syscall`,而 ARM 的可能叫 `svc`)。为了兼顾“跨平台”和“硬件控制”,Linux 内核源码巧妙地分为了两部分:
283+
但是,虽然我们说操作系统可以等同于图中的 C 代码,但物理芯片毕竟存在硬件差异(比如 x86 的特权指令叫 `syscall`,而 ARM 的可能叫 `svc`)。为了兼顾“跨平台”和“硬件控制”,Linux 内核源码巧妙地分为了两部分:
258284

259285
- **95% 的通用 C 代码(与指令集无关):** 操作系统的绝大部分逻辑(比如文件系统怎么读写文件、网络 TCP/IP 协议怎么发包、进程调度的算法模型)都是纯粹的逻辑。这些 C 代码可以直接喂给图中的 x86 工具链或 ARM 工具链,编译器会自动把它们翻译成对应芯片的机器码。
260-
- **5% 的架构专属代码(与指令集强绑定):** 涉及到直接操作硬件底层的极小部分代码(比如开机启动的第一段引导代码、内存 MMU 页表的底层设定、上下文切换时保存寄存器),必须针对不同的芯片手写**特定的汇编语言**或调用特定的硬件指令。
286+
- **5% 的架构专属代码(与指令集强绑定):** 涉及到直接操作硬件底层的极小部分代码(比如开机启动的第一段引导代码、内存 MMU 页表的底层设定、上下文切换时保存寄存器),必须针对不同的芯片手写**特定的汇编语言**或调用特定的硬件指令。
287+
288+
```mermaid
289+
graph TD
290+
subgraph "OS 源码层 (C语言文件)"
291+
Code95["95% 通用代码: a = b + 1"]
292+
Code5["5% 专属代码: (目标: 开启MMU分页)"]
293+
end
294+
295+
subgraph "GCC 编译器的处理路径"
296+
%% 95% 的顺畅路径
297+
Code95 -->|"1-语法解析: C语言认识加法"| GCC_Translate["GCC 正常查字典翻译"]
298+
GCC_Translate -->|"x86后端"| Gen_X86_ADD["生成 x86 机器码 (ADD)"]
299+
GCC_Translate -->|"ARM后端"| Gen_ARM_ADD["生成 ARM 机器码 (ADD)"]
300+
301+
%% 5% 的碰壁路径
302+
Code5 -->|"2-语法解析: C语言里没有控制MMU的语法"| GCC_Fail{"GCC: 我该怎么翻译?"}
303+
GCC_Fail -->|"被迫硬编码"| HandCode["内核工程师只能针对芯片手写内联汇编"]
304+
305+
HandCode -->|"如果是 x86 架构"| ASM_X86["手写: __asm__('mov cr3, rax')"]
306+
HandCode -->|"如果是 ARM 架构"| ASM_ARM["手写: __asm__('msr ttbr0_el1, x0')"]
307+
308+
ASM_X86 -->|"GCC 放弃翻译,直接照抄"| Direct_X86["直接输出 x86 特权机器码"]
309+
ASM_ARM -->|"GCC 放弃翻译,直接照抄"| Direct_ARM["直接输出 ARM 特权机器码"]
310+
end
311+
```
312+
313+
314+
**为什么必须手写那 5%?**
315+
316+
**场景一:如何告诉芯片“页表”在哪里?** 操作系统要维护一张页表(地图)。当页表建好后,操作系统必须把这张地图的起始地址告诉物理芯片(CPU),这样 MMU 才能开始工作。
317+
318+
- **在 x86 芯片上:** 硬件规定,这个地址必须塞进一个叫 `CR3` 的特权寄存器里。
319+
- **在 ARM 芯片上:** 硬件规定,这个地址必须塞进一个叫 `TTBR0` 的特权寄存器里。
320+
- **GCC 的困境:** 标准的 C 语言里根本没有 `CR3``TTBR0` 这种变量类型或关键字!你如果写 `CR3 = 0x4000;`,GCC 只会报一个极其弱智的错:“变量 CR3 未定义”。
321+
- **解决办法(那 5% 的代码):** Linus Torvalds 只能在 `arch/x86` 目录下建一个文件,用 C 语言包裹着一句极其硬核的 x86 汇编:`__asm__("mov %0, %%cr3" : : "r" (address));`。GCC 看到 `__asm__` 就懂了:“哦,这是方言,我不翻译了,我直接把这段机器码塞进去。”
322+
323+
324+
**场景二:如何触发系统调用?** 我们前面提到了 `fork()` 最终会触发硬件的中断通道陷入内核。
325+
326+
- **x86 的指令是:** `syscall`
327+
- **ARM 的指令是:** `svc #0`
328+
- **GCC 的困境:** C 语言标准里根本没有“陷入内核”这个语法。GCC 作为一个通用翻译官,它不知道你想让程序跨越权限边界。所以内核开发者必须再次手写汇编,专门针对 x86 写一遍 `syscall`,再针对 ARM 写一遍 `svc`

0 commit comments

Comments
 (0)