ARTICLE · 1223320
阿波罗11号登月源码竟然开源了!仅靠4KB内存,把人类送上月球!
阿波罗 11 号登月飞船的完整代码,最近又小火了一把!
其实它早就在 GitHub 上开源了,每隔几年都会被翻出来刷一次屏。

最硬核的是,这套登月代码的运行内存小得可怜,仅有 4 KB。
就连存放整套程序的只读存储器,也只有约 72 KB,还不如一张手机截图大。
在如此有限的条件下,1969 年的工程师居然用汇编一行行写出了一整套飞控系统!
真是螺蛳壳里做道场,太强了...

仓库名叫 chrislgarry/Apollo-11,截至 2026 年,已经有 7.5 万个 Star。
仓库链接:https://github.com/chrislgarry/Apollo-11
于是,我把这个仓库又又又从头到尾翻了一遍,发现了很多有意思的细节。
一、基础结构
仓库里有两套核心程序:负责指令舱的 Comanche055(Colossus 2A),和负责“鹰号”登月舱的 Luminary099(Luminary 1A)。
程序各约 6.5 万行(含注释),各有 90 个左右的文件,全部平铺在一个目录里,没有子文件夹。
它本质上是从头到尾一次性汇编,不像现代项目那样拆成独立模块。

底层是操作系统:
EXECUTIVE(任务调度)、WAITLIST(定时任务)、中断处理、重启恢复。中间层是公共能力:
INTERPRETER(虚拟机)、各种数学子程序、PINBALL_GAME_BUTTONS_AND_LIGHTS(键盘和显示)。上层是具体任务,文件直接按程序编号命名,比如
P20-P25、P40-P47、P51-P53。这些编号和宇航员在键盘上输入的程序号是一一对应的,P63 就是登月下降。
看起来平平无奇,实则每一层的设计都非常精妙,我们逐个拆解这套代码的关键设计,你就会理解 4KB内存是怎么把人送上月球的。
二、极限内存和储存
4KB运行内存,72 KB 储存登月,怎么做到的?
首先了解一下他们用的计算机,是阿波罗导航计算机。
这台计算机重约 32 千克,功耗仅 55 瓦,主频约 2.048 MHz,是最早采用集成电路的计算机之一。

今天的电脑和手机普遍数据按 8 位一个字节来存。
而 AGC 一个字只有 15 位数据,外加 1 位用来查错的奇偶校验位,连“字节”这个概念都没有。
也没有浮点数,程序员只能自己记住每个数的小数点在哪。

阿波罗机载飞行软件团队负责人玛格丽特·汉密尔顿
所以,在这样一台机器上写登月程序,其实是非常困难的。
我翻了专门分配内存的 ERASABLE_ASSIGNMENTS.agc 和调度程序 EXECUTIVE.agc,发现 60 年代的程序员为了把这点内存用到极致,想了两个办法:
第一,同一块内存按阶段轮流用。
翻到这个文件的开头可以发现,他们给大量内存位置标了“身份”。
PRM 表示整个任务期间专用;TMP 表示可以临时借用,不同时运行的程序能共用同一块。

光是登月舱程序,就标注了 1500 个变量。
而且每个变量还有不同注释,写明它可以和谁共用,不能和谁共用。
比如有的写着“可以覆盖,但要小心,只在动力下降时使用”,有的写着“不能覆盖 RONE 和 VONE”。

第二,每个任务只给 12 个字的空间。
登月过程中,计算机要同时做好几个任务,比如导航计算、发动机控制、姿态调整。
但它不会临时给任务分配内存,而是提前切好 8 个“任务槽”。
每个槽 12 个字,相当于一个极简的进程上下文。
当前任务固定在 0 号槽,切换任务只需交换两个槽的 12 个字。

要做向量、矩阵这类复杂运算的任务,还能再领一块 44 个字的“草稿区”。
但一共只有 5 块,用不着的任务一个字都不多给。
算下来,整套多任务系统只占了大约 340 个字,用六分之一的内存,就能让这台计算机实现多任务调度。

而 72KB的储存则更硬核,是用铜线织出来的。
那时候没有闪存芯片,大家的选择不多,只能选择磁芯绳存储器。
这是一种纯手工制作的存储器。甚至没有通电写入这个功能,数据就是它的物理结构本身。
代码定稿后,会被送到工厂。
由女工们坐在放大镜前,拿着细细的铜线,对着一排排微小的磁环穿针引线,铜线从磁环中间穿过代表 1,从旁边绕过代表 0,这样储存一整套登月程序。

女工穿线
铜绳一旦织好,就再也改不了,更没法在线打补丁。所以,代码结构必须万分严谨,不能有冗余。
翻开 FIXED_FIXED_CONSTANT_POOL.agc,能看到代码中刻意去重的地方。
有不少常数直接引用别处已有的位置,比如说数字 4、数字 11,都可以借用键盘显示程序里现成的存储单元。

更有意思的是,常数的相邻关系也被利用了,负零放在零前面,两个字连起来,又能作为一个双精度常数使用。

而最大的一笔减法,是在这台机器里被塞进了一台“虚拟机”。
二、波兰虚拟机
翻开 INTERPRETER.agc 文件,会发现一个更疯狂的设计。
前面说到的阿波罗导航计算机,它天生只认识 8 条基本指令,甚至无法直接进行向量和矩阵运算,连乘除法都要借助额外的前缀指令才能完成。
但是,我们必须要让它算出三维空间里的登月轨道,怎么办?

在这样的硬件条件之上,60年代的程序员硬生生用汇编写出了一套解释器。
按源码粗略估算,它只占了约 2000 个字的程序存储,却能直接处理 28 位的双精度数,以及由 6 个字组成的三维向量。
只要在汇编里写一行 TC INTPRET,这台 15 位的机器就会切换进虚拟机模式,点乘(DOT)、叉乘(VXV)、单位化(UNIT)、矩阵乘向量(MXV),都只要一条指令。

为了省空间,这台虚拟机也处处精打细算。

一是一个字塞两条指令。
虚拟机的操作码只有 7 位,最多能编 128 种运算。
汇编器会把相邻的两条打包进同一个 15 位的字里,指令部分的空间直接省下一半。
二是用正负号省掉地址。
虚拟机采用不需要括号的波兰表示法,操作码字存储时被取反,是负数;内存地址则是正数。
需要取操作数时,它会先偷看下一个字。
是正数,就去那个地址取数;是负数,说明程序员没写地址,下一个字已经是新指令了。
它就直接从栈里弹出上一步的结果,接着算。
三、软重启机制
还有一部分值得说,就是藏在 RESTART_TABLES.agc 里的软重启机制。
1969 年 7 月 20 日,“鹰号”登月舱下降途中,发生了惊心动魄的一幕。
离月面还有约 1 万米时,计算机突然报警。

阿波罗登月器导航计算机专家杰克:加尔曼在发射前模拟导致着陆中止后,编写了一份备忘单,列出了警报代码。史蒂夫·贝尔斯在阿波罗11号登陆时将这份副本贴在他的控制台上。
警报一共响了 5 次,大部分是 1202,中间还夹着一次 1201。
OCT1201#NOVACAREAS.OCT1202#NOCORESETSAVAILABLE.1202 是“任务槽用完了”,1201 是“草稿区用完了”。
前面说的那 8 个任务槽、5 块草稿区,在登月最关键的时刻被挤满了。
换成很多计算机,这时候大概已经死机了。
但阿波罗计算机很快就恢复了工作,导航和发动机控制几乎没受影响,这全部归功于程序设计的软重启机制。

它的思路很简单:关键任务每走到一个重要步骤,都会调用一次 PHASCHNG,记下“我是第几组任务、走到了第几步”。
这些断点都保存在内存里,重启也不会丢。
一旦撑不住,计算机就进入报警程序 BAILOUT,记下报警代码,再跳到软重启入口 ENEMA。
把堵住的任务一口气清空,再按断点记录,把导航、发动机控制这些关键任务重新拉起来。
飞船就这样在一次次重启中,继续稳稳地往下降。
四、彩蛋
翻到注释里,你会发现这群 60 年代的程序员其实非常好玩。
登月舱的主点火程序,文件名叫 BURN_BABY_BURN--MASTER_IGNITION_ROUTINE.agc,直译过来就是“燃烧吧宝贝燃烧,主点火程序”。
这句话来自 60 年代的灵魂乐 DJ Magnificent Montague,他每次播到最火的新歌,都会大喊一句“Burn, baby! BURN!”,写点火程序的 Don Eyles 和 Peter Adler 就顺手借来当了名字。

点火参数表上方还写着一句 NOLI SE TANGERE,化用《圣经》里的“不要碰我”,意思是这张表谁也别乱动。
登月程序 THE_LUNAR_LANDING.agc 里的注释更逗。
计算机提示宇航员手动转动雷达天线时,注释写着“PLEASE CRANK THE SILLY THING AROUND”(请把这破玩意儿转过来)。
宇航员按了确认,它还要再查一遍,注释写着“SEE IF HE’S LYING”(看看他是不是在骗人)。
确认无误后,程序跳转去点火,注释则写着“OFF TO SEE THE WIZARD...”(去见魔法师了),化用的是电影《绿野仙踪》里的经典歌名。

有意思的是,全篇搜不到一个 TODO 或 FIXME,可能因为在登月这件事上,没人敢把问题留到以后。
最后说说这份代码是怎么来的。
它不是 NASA 从哪块硬盘里导出来的,而是一摞存放在 MIT 博物馆里的纸质打印稿。
翻开任意一个文件的开头,都能看到这样一段说明:

代码由飞行历史学者 Paul Fjeld 在博物馆逐页拍照,由博物馆的 Deborah Douglas 协助安排,再由 Virtual AGC 项目的 Ron Burkey 带着志愿者,对着照片一个字符一个字符敲回电脑,最后用汇编器 yaYUL 重新编译验证。
登月舱程序的打印稿上,还印着当年的汇编时间:1969 年 7 月 14 日 16 点 27 分。
也就是说,这份代码定稿时,离阿波罗 11 号发射只剩两天。
五、结尾
chrislgarry/Apollo-11 这个仓库,每隔几年就会被新一代程序员重新翻出来膜拜。
为什么在拥有千亿参数大模型、几十 GB 内存手机的今天,我们看着五十多年前的八进制汇编,依然会起一身鸡皮疙瘩?
因为极度的匮乏,逼出了极致的优雅。
今天的我们太富有了。内存不够?加内存条。
代码跑得慢?升级显卡。
有 Bug?先上线,等用户报错了再打补丁。
我们在海量算力的温床里,写出了越来越臃肿、越来越脆弱的软件。
而打开阿波罗 11 号的源码,你会看到另一个世界。
在那个只有 4 KB 内存、连改一行代码都要剪断铜线的年代,一群平均年龄二十多岁的年轻人,在针尖上跳出了一支零失误的芭蕾。
在这堆发黄的汇编指令背后,是人类在算力荒原上,仅凭智慧、纪律与勇气,向星辰大海递出的第一封信。















































































