你知道 Linux 内核有一个 1997 年就引入的特性,让 Apple Silicon Mac 能高效运行 x86 容器吗?
它叫 binfmt_misc,Linux 2.1.43 引入,距今快 30 年了。
原理极其简单: Linux 内核在执行一个二进制文件时,会先读取文件头的 magic number。如果你提前在 /proc/sys/fs/binfmt_misc/ 注册了一条规则 —— "遇到这种 magic 的文件,交给某个解释器处理" ——
内核就会自动把执行权转交给那个解释器。和 #!/bin/bash 的 shebang 机制本质一样,只是匹配的是二进制文件头。
最早它是用来让 Linux 直接 "运行" Java class 文件和 Windows PE 可执行文件的。后来 QEMU 利用这个机制实现了用户态跨架构模拟 —— 在 ARM 的 Linux 上直接执行 x86 ELF,内核自动调用 qemu-x86_64
翻译。
然后 Apple 来了。在 Apple Silicon Mac 上用 Colima / Lima 启动一个 Linux VM(使用 macOS 的 Virtualization.framework),打开 rosetta: true 后,会发生这些事:
1. macOS 通过 virtio-fs 把 Rosetta 翻译器二进制挂载进 Linux VM 的 /mnt/lima-rosetta/rosetta
2. VM 内部用标准的 binfmt_misc 注册一条规则:遇到 x86_64 ELF magic (7f454c46...02003e00),交给 /mnt/lima-rosetta/rosetta 处理
3. 从此,VM 里任何 x86_64 二进制的执行都会被内核自动转交给 Rosetta 翻译
对容器来说完全透明 —— docker run --platform linux/amd64 nginx,Docker 拉下来的是 x86 镜像,容器里的进程是 x86 ELF,Linux 内核通过 binfmt_misc 自动调用 Rosetta
翻译执行。容器自己完全不知道发生了什么。
性能对比:
- Rosetta 方案:接近原生 70-90% 的性能(JIT 翻译,指令级优化)
- QEMU 全虚拟化方案:仅约 10-30%(完整模拟 x86 CPU)
一个 1997 年为了跑 Java class 文件设计的内核特性,在 2024 年成了 Apple Silicon 跑 x86 容器的关键基础设施。有时候最持久的架构决策,就是那些足够简单、足够通用的抽象。
$ colima ssh
$ cat /proc/sys/fs/binfmt_misc/rosetta
enabled
interpreter /mnt/lima-rosetta/rosetta
flags: OCF
magic 7f454c4602010100000000000000000002003e00