Saturday, January 26, 2019

Building GCC 1.27

GCC 1.27 was released in 1988 and is the first version of GCC supporting the x86 CPU. I thought it would be fun to make it work on my desktop computer.

Mikhail Maltsev wrote a great blog post about this a while back “Building and using a 29-year-old compiler on a modern system”. I used Mikhail’s work as a starting point, but I built on a 64-bit Ubuntu system so I needed to update paths and as/ld options for running on a 64-bit OS, and I had much bigger problems with the ancient GCC not understanding the system headers. I also enabled the DBX debug format instead of the UNIX/32V SDB format that GDB does not understand. But I did not need to make that big changes to Mikhail’s patch.

It is amazing how well things work – the modern assembler, linker, and debugger handles the code generated by GCC 1.27 without any problems. And command options such as -O, -E, -S, -c, -g, -W, -pedantic, and -fomit-frame-pointer does what you expect from using a modern GCC. All the options are documented in the manual page – you can format the text by passing the gcc.1 file to man as
man -l gcc.1

How to build GCC 1.27 on Ubuntu

I have built the compiler on 64-bit Ubuntu Desktop 16.04 as described below.


GCC 1.27 is a 32-bit program, so we need to install 32-bit compiler and runtime support
sudo apt install gcc-multilib

Downloading and preparing the source code

Download the source code and the patch, and apply the patch as
tar xf gcc-1.27.tar.bz2 
cd gcc-1.27
patch -p1 < ../gcc-1.27.patch

Configuring the source code

The compiler is configured by setting up symbolic links to the correct configuration files
ln -s config-i386v.h config.h
ln -s tm-i386v.h tm.h
ln -s md
ln -s output-i386.c aux-output.c
You may want to change where the compiler is installed by updating bindir and libdir in the Makefile. I set them to
bindir = /home/kristerw/compilers/gcc-1.27/bin
libdir = /home/kristerw/compilers/gcc-1.27/lib

Build and install

The compiler is built in two (or three) stages, We start by building it using the system compiler
We then build it again using the newly built compiler
make stage1
make CC=stage1/gcc CFLAGS="-O -Bstage1/ -Iinclude"
As a third, optional, step, we build it again using the second compiler and checks that the resulting binaries are identical with the second compiler (if not, then the compiler has miscompiled itself).
make stage2
make CC=stage2/gcc CFLAGS="-O -Bstage2/ -Iinclude"
diff cpp stage2/cpp
diff gcc stage2/gcc
diff cc1 stage2/cc1
We are now ready to install the compiler
make install