From a 1998 source dump to a clean-room Rust IRIX

Automation & AI

From a 1998 source dump to a clean-room Rust IRIX

The 6.5.7m kernel rebuilt from its source dump, the binary-only drivers relinked, and a Ghidra fork taught to read MIPSpro binaries.

Problem

The IRIX 6.5.7m customer source release cannot build a complete system on its own. It ships stubs for the graphics and audio subsystems, which SGI supplied as binaries only. No current compiler targets IRIX either: GCC removed the target in version 4.7, and MIPSpro is binary-only and runs only on IRIX. The binaries are the only documentation for the hardware they drive.

Diagnosis

  • The install media still ships the real drivers unstripped, with symbols, inside .sw images that come with checksummed manifests. Where the 6.5.7m overlay re-ships a module, that revision is the canonical one.
  • Stock Ghidra dies on every MIPSpro object with the same EOFException: SGI's DWARF dialect omits the end-of-table marker and concatenates per-unit blocks.
  • N32 objects imported as 32-bit MIPS truncate: 71 of 101 functions in one archive, with a 1,548-byte function looking like a 28-byte stub.
  • binutils 2.47 regresses three ways: it no longer creates .rld_map, it emits a DT_MIPS_RLD_MAP_REL entry the IRIX loader has never seen, and it floors the captured crt1.o .init alignment of 27 to 1.

Action

  • Assembled MIPSpro 7.3 by hand on an emulated Indy, then fixed three bootstrap bugs before the kernel would link: a stale 0-byte spec, an lboot from the wrong vintage, and one missing defs line.
  • Extracted the binary-only modules from the install media's .sw images, verified them against the manifests, and relinked the kernel with the real drivers.
  • Patched a Ghidra 12.1.2 fork: DWARF abbreviation parsing, function bodies from DWARF ranges, ECOFF stabs, MIPS small-common symbols, and inline dispatch tables.
  • Carried a GCC 16.2 and binutils 2.47 patch series so the tree builds from a Linux host.

Outcome

  • unix.kdebug: 9,833,128 bytes, ELF32 big-endian N32, and it booted first try.
  • The relinked kernel grew from 9.8 to 10.4 MB and reports Graphics board: Indy 24-bit; Xsgi starts on it.
  • Hand-written assembly bodies matching their DWARF ranges went from 285 of 366 to 366 of 366.
  • The 6.5.22 kernel imports as 10,188 functions, all named, with 12,763 types; libGLcore decompiles with zero unnamed FUN_ stubs.
  • The GCC cross builds o32 and n32 objects, libc and libm rebuild from the tree, and a static hello runs on the guest.

What I'd do differently

Long commands go in a script file now, never down a serial console; a mangled rm -rf once deleted /etc and fifteen /var directories.

Next is the 6.5.22 fold: decompile those binaries and bring the differences back into the tree. Then the Rust port, which stays clean-room by design. Source to AST to Rust, verified against behaviour, so no SGI code travels into the result and the finished OS can ship under its own licence.

Clock
--:--:--—Local time