Halt and Catch Fire: The History of the 'Illegal Opcode'

雖然現在許多人將 Halt and Catch Fire 視為一部關於個人電腦革命、廣受好評的 AMC 電視影集,但這個詞源於更古老的工程幽默與硬體不穩定性的傳統。在計算機發展的早期,「Halt and Catch Fire」(HCF)成為了一種簡稱,用來描述導致 CPU 停止執行有用工作的機器碼,讓操作者別無選擇,只能重新啟動機器。

The Anatomy of an Illegal Opcode

HCF 的核心在於描述處理器遇到未經文件記載或無效的 opcode 時的狀態——即硬體不知道如何處理的位元模式。在設計完美的系統中,無效的 opcode 應該會觸發異常(exception)或受控的停機(halt)。然而,在早期的矽晶片中,這些指令集中的「漏洞」往往會導致不可預測的行為。

從歷史上看,這個詞部分是對標準的三字母組合語言助記符(如 ADDCMPJMP)的一種戲弄。它與當時其他的程式設計師笑話並列,例如:

  • EPI: Execute Programmer Immediately
  • DC: Divide and Conquer
  • CRN: Convert to Roman Numerals

The Motorola 6800 and the 'Bus-Walking' Bug

對於 Motorola 6800 而言,HCF 從一個笑話轉變為了一種有紀錄的硬體特性。該晶片具有 256 個單位元組的 opcode,但只有 197 個是正式記錄在案的。這留下了 59 個位元模式,晶片會以未經文件記載的方式進行解碼。

在 1977 年的 BYTE 雜誌文章中,Gerry Wheeler 指出兩個特定的位元組——$9D$DD——會觸發災難性的故障。當這些 opcode 被執行時,處理器不再表現得像一個 fetch-decode-execute 引擎。相反地,程式計數器(program counter)會無限增長,且晶片會持續向位址匯流排(address bus)發出讀取請求。

正如 Wheeler 所描述的:

當執行此指令時,唯一的觀察方式是使用示波器。從使用者的角度來看,機器會停機,且幾乎無法重新啟動。那些在位址匯流排上裝有指示燈的人會看到處理器開始非常快速地、依序讀取所有記憶體。實際上,位址匯流排變成了一個 16 bit counter。

有趣的是,這種行為並不總是見被視為缺陷。Motorola 工程師後來在 IEEE Design & Test (1985) 中透露,這種狀態的內部暱稱是 HACOF。因為這種「匯流排漫步」(bus-walking)行為實際上是在掃描 RAM,因此產品工程部門決定將其保留作為在啟動過程中測試記憶體的快速方法,而不是耗費資源去移除這個 bug。

From Core Memory to Modern Fuzzing

「catch fire」的部分通常被認為是誇張修辭,但它有著物理現實的根源。一些說法指出,在 IBM System/360 上,某些無效的 opcode 會導致系統極速存取磁芯記憶體(magnetic core memory)中的特定位置,以至於硬體會過熱並發生物理性的起火。

雖然有些懷疑論者將其視為都市傳說,但由於軟體錯誤導致硬體故障的風險在早期計算機中是真實存在的。

其他類似的故障也出現在各種架構中:

  • The 6502: 具有可能鎖死 CPU 的非法 opcode。
  • The Pentium F00F Bug: 一個著名的缺陷,特定的位元組序列可以鎖死處理器。
  • CRT Burn-in: 在 Commodore PET 4032 中,不當的 POKE 指令可能會停止 CRT 掃描線(raster scan),使電子束停留在一個點上,並在幾分鐘內燒毀螢幕上的磷光體。

今天,這種遺產以 fuzzing 的形式延續。現代安全研究人員使用 fuzzing 來向處理器輸入隨機或不及預期的數據,以識別無效狀態、漏洞或硬體 bug,這本質上是尋找下一個 HCF 指令的高科技版本。

Reflections on the Hardware Era

對 HCF 的著迷反映了一個軟體與硬體邊界模糊的時代。正如一位觀察者所言,80 與 90 年代提供了一種奇妙的感覺,開發者可以「親手接觸硬體,並在很大程度上理解硬體與軟體都在做什麼」。

在一個充滿高階抽象與雲端運算的時代,我們很容易忘記,每一行程式碼最終都會轉化為在矽晶片中移動的電訊號。正如「Halt and Catch Fire」的歷史所展示的,邏輯錯誤與物理災難之間的距離,有時比我們想像的還要短。

Sources