So, in a previous post, I claimed static binaries “last forever”. The oldest binaries I have to hand are from 2006. These were either RedHat or Suse, but I don’t remember which. We were transitioning to Suse at around that time.
Anyway, they work. At least the Linux/x86 one does. I don’t have a handy PPC machine or SGI or Sun around to try the more exotic architectures. I mostly keep those binaries up to buff my nerd credentials. Anyway point is, the 14 year old binary works just fine.
So how old will it go?
I do remember there was a “compatibility break” between libc5 and glibc back in the day, but that was with dynamically linked code. I remember though one could fix it by finding the loader and libc from an old system and simply copying them across.
Time to dig out an old static executable!
Hm, well, no idea where I’d find one. The easiest way is to make one. Sadly, because I’m not a complete tech hoarder I threw away my RedHat 5.2 CDs which came in a spiffy box set for something like £50 at the local bookshop, bundled with a bunch of books on CD. Best £50 I ever spent; it’s what got me into Linux.

Fortunately good Linux vendors still make their ancient distributions available for historic interest and presumably maintenance of ancient systems. RedHat are among them and so for old time’s sake I’ll install RedHat 5.2.
The easiest way is to start with QEmu. First thing to do is to make a disk image. I think I installed it on my brand new lavishly huge 9G drive. I reckon 1G is OK, since it came on a CD:
qemu-img create deadrat-5.2.img 1G
You’ll then need the boot image (boot.img
) and as I discovered after some trial and error, the supplemental floppy image (supp.img
) from here:
ftp://archive.download.redhat.com/pub/redhat/linux/5.2/en/os/i386/images/
FTP for the win! I’m using FTP since it’s necessary for later. RedHat no longer offers the ISO mages to download, so I can’t grab one and do a CD install. They do however have the FTP server still running (see above) so you can do an FTP install if you have network access. A little bit of trial and error found me this incantation of QEmu to get on the ‘net:
qemu-system-i386 -fda boot.img -hda deadrat-5.2.img -netdev user,id=mynet0 -device ne2k_pci,netdev=mynet0
This emulates an NE2000 PCI network card, a popular model with many almost compatible clones in the mid 90s. So…
OK now to try some very old school 1997 era C++ code (/tmp/prog.cc
):
#include <iostream.h> int main(){ cout << "Hello world.\n"; }
Don’t complain it’s not standards compliant, there wasn’t a standard in 1997. And compile it, check it and run it:
[root@hax /tmp]# g++ --version egcs-2.90.29 980515 (egcs-1.0.3 releae) [root@hax /tmp]# g++ -static prog.cc [root@hax /tmp]# ldd a.out not a dynamic executable [root@hax /tmp]# ./a.out Hello, world.
OK seems to work. Now to get that file onto my machine. First power it off, then mount it. Mounting isn’t completely trivial since you first need to examine the partition table and pass in an offset to the loopback device before mounting:
$ fdisk -lu deadrat-5.2.img Disk deadrat-5.2.img: 1 GiB, 1073741824 bytes, 2097152 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x00000000 Device Boot Start End Sectors Size Id Type deadrat-5.2.img1 63 34271 34209 16.7M 83 Linux deadrat-5.2.img2 34272 2064383 2030112 991.3M 5 Extended deadrat-5.2.img5 34335 1997855 1963521 958.8M 83 Linux deadrat-5.2.img6 1997919 2064383 66465 32.5M 82 Linux swap / Solaris $ sudo losetup -o $((512 * 34335)) /dev/loop99 deadrat-5.2.img $ sudo mount /dev/loop99 /mnt/
And running it…
$ cd /mnt/prog $ ./a.out Hello, world.
Woahhhhh. A 24 year old (well simulated) just runs on a current Linux machine. Actually mostly, the whole thing runs. I can chroot to it and just run stuff. It takes a little setup: modern Ubuntu seems to have blocked TCP access to the X server, so I have to bind mount /tmp to /mnt/tmp. But once that’s done, I can just run stuff! For example:

Static executables just work. Dynamic ones are harder, they work but not without a chroot because while the kernel mostly maintains compatibility, libc does not.
But anyway, point proven. Static executables just work out of the box 24 years later. I wonder if my docker images will work in a quarter of a century’s time…