Building a MIPS Compiler for Windows on a Linux VM!

I’ve tried to build a cross compiler on MinGW32 before, and despite there being obvious steps on how to do it, I’ve never gotten it to work.  Now I’ve built cross compilers before so it’s not like I don’t have any clue on what I’m doing, but the problem is that Windows isn’t UNIX, and I don’t want to use Cygwin.

So that enters another fun possibility known as the Canadian Cross, which is using a machine in the middle to build a compiler.  As we all know, Linux is great for building and running GNU software, so a Linux machine to build my cross compiler would be the best.  Now the whole point of this is that I wanted to build a MIPS program to run on Dynamips.  And through a LOT of googling, I managed to find this program called CILO the cisco Linux loader.  Now as far as I can tell the people trying to port Linux the the MIPS based cisco routers (3600 and 7200) never succeed, but they did manage to leave this bootloader behind.  And compiling it was very tricky as they gave no hints on what to use.  So with a lot of trial and error I found that binutils 2.18 is the minimal version that will work as the code depends on being able to do register aliasing which isn’t present in previous versions.  Also according to this, they were using gcc 4.1.2 in their Linux port. So with some luck I did mange to get CILO to build with a cross compiler on Linux.  Which was pretty awesome to see Dynamips run a C program!

But that doesn’t help me on the Windows side.

Now the first thing that I’d normally do is install the default MinGW cross tools, but because I need ancient binutils and GCC support as newer versions not only won’t work for what I want, but won’t build older versions I tried to keep things in step.  This meant on Linux I first had to build a Linux to Windows cross compiler using binutils version 2.25.1 and GCC version 4.1.2 . Configuring and building binutils was a snap with:

./configure --target=i686-mingw32 --prefix=/usr/local/mingw32

And configuring and building gcc was also a snap with:

./configure --target=i686-mingw32 --prefix=/usr/local/mingw32 --disable-libssp

I thought I could just use a new mingwrt and w32api but that proved disastrous as the newer libs gave me this fun error on trying to link a Win32 execuatable:

 undefined reference to `___chkstk_ms’

And googling that around the consensus is that your binutils, and gcc is too old, and upgrade, granpa!  But I want old software so I naturally have to just use older versions, and for gcc 4.1.2 I wanted:

  • mingwrt-3.18-mingw32-dev.tar.gz
  • w32api-3.15-1.mingw32-dev.tar.lzma

Now I could build and link and test my Linux to Windows toolchain!

Now for the crazy part.

First I need a binutils, so I configured binutils 2.18 like this:

./configure --host=i686-mingw32 --target=mips-elf --prefix=/mips

And sure enough with a little prodding I had a MIPS assembler/linker/librarian and all that fun stuff!

Next was a little (ok a LOT) more fun which was building gcc.

After about 30 aborted attempts I finally got gcc to build with this:

./configure --target=mips-elf --prefix=/mips --disable-libssp --build=i486-linux-gnu --host=i686-mingw32

The fun part of course is that during the build, gcc will want to run the cross compiler and dump it’s host machine bit types by running ‘xgcc -dumpspecs’.  Well thankfully via wine, Linux can run Win32 execuatables so I saved myself a few minutes by not having to copy over the partial compiler, and run the command, and transfer the results back.

So with a bit more hand holding on the build I finally got it to finish compiling by linking /bin/true to fix-headers .  What a mission.  Now I excitedly transfered my build to my Windows host, and setup some environment variables and built the hello world cisco application, and, it worked! (well crashes the same way as the pre-built one, but it does say:

C7200 ‘default’: starting simulation (CPU0 PC=0xffffffffbfc00000), JIT disabled.
ROMMON emulation microcode.

Launching IOS image at 0x80008000…
Hello World!
Image returned to ROM.
Reset in progress…

Which is pretty cool!

I tried to merge in a make utility but that turned out to be kind of screwed up, so I just copied the cross steps from Linux, and now I can build cilo on Windows!

C7200 ‘default’: starting simulation (CPU0 PC=0xffffffffbfc00000), JIT disabled.
ROMMON emulation microcode.

Launching IOS image at 0x8000d2e4…
CIL
Error: Unable to find any valid flash! Aborting load.
Image returned to ROM.
Reset in progress…

It may not look like much, but It is running the program!  Dynamips is missing a bunch of hardware, like flash.  Or I found out the ability to read from the console using the promlib.  But it can print to it at least.

So for those who want to give it a try, here is my MIPS-ELF tool-chain for Win32, that includes the cisco loader!

Stupid error building binutils

So I’m starting a new VM, and after installing Debian, and the important packages, build-essential and the Linux headers…

#  apt-get install build-essential linux-headers-$(uname -r)

I got this fine error trying to build binutils:

gcc -g -O2 -o sysinfo sysinfo.o syslex.o
syslex.o: In function `main’:
/usr/src/binutils-build/syslex.c:1: multiple definition of `main’
sysinfo.o:/usr/src/binutils-2.22-human68k/sysinfo.c:1: first defined here
collect2: ld returned 1 exit status

Turns out I didn’t have bison/flex installed.  Oops!

Oh well easy enough to solve.

#apt-get install bison flex

Otherwise, remember to build binutils/gcc in it’s own directory or that’ll cause other fun down the line.

Don’t forget you need GMP 4.2+, MPFR 2.3.1+ and MPC 0.8.0+ to build GCC…

#  apt-get install libgmp-dev libmpfr-dev libmpc-dev

Tracking down the InfoTaskForce from 1987.

So like all zork obsessed people (I really should get help or something), I was trying to build a z-machine interpreter for the x68000, using Lydux’s cross GCC compiler.  And it was honestly looking like a LOT of work in the IO department.  Thinking that the older versions were more simpler, I went looking for the oldest open Z-machine, called the “The InfoTaskForce Infocom interpreter”, released by the InfoTaskForce.  Unfortunately I can only find version 4.01 searching for the source code.  Which still looks too complicated.  But looking the history file, the project started back in 1987.  So with that to go on a new google search got me this:

Infocom Adventure Executor Source Files (1987)(InfoTaskForce)[C].zip

From an TRS-80 dump of all things.  I don’t know what version this is other than the brief copyright mention:

/* (C)opyright 1987 InfoTaskforce. */

All of the files are dated 4/12/2001 so they obviously aren’t original. And the version string is:

echo ( “Interpreter: C Version 1.0\n” ) ;

So assuming this is correct, from the 4.01 history file:

REV_E – June 25, 1987.
———————-

REV_E is the first major overhaul to the interpreter.

* The source is now significantly lint free.

* TERMCAP support has now been added [#define TERMCAP option].

* Screen paging and word wrap has been added, along with a new
command line option which disables screen paging (-p).

* Random number generator seeding using time () added [#define
TIMESEED option].

* Attributes in the object list are listed as bits.

* A debuging version can now be produced as an inbuilt options
[#define DEBUG option].

* The coded requirement that 25k is always free in the system can
now be removed [#define ALLOCALL option].

* A new command line option was added to print the object/room list
as a tree (-r).

* interp.c has been re-written to improve efficiency [large
switches have been replaced with arrays of pointers to funcions].

There are now 14 machines on the porting list:

Machine C Compiler Operational Porting details

128K Apple
Macintosh Aztec C Version 1.06F 18/05/87

128K Apple
Macintosh Lightspeed C 2.01 29/05/87 Use “rb” & “wb” in all fopen()s

IBM PC/AT Microsoft C 4 30/05/87 Link with binmode.obj

DEC VAX 11/780 UNIX V7 cc 01/06/87

HP-9000 HP-UX cc 02/06/87

gould cc 03/06/87

Amiga Aztec C 04/06/87

Pyramid 9810 cc 04/06/87

Pyramid 90x cc 04/06/87

Osiris cc 05/06/87

DEC PDP-11/? UNIX V? cc 07/06/87 EXTENSIVE
mods to fix problems with signed chars.

VAX VMS cc 16/06/87 Add #define
times ttmes to fix multiply defined symbol problem. [infocom.h]

Version 1.00 – August 17, 1987.
——————————-

The REV_C interpreter of June 2, 1987 was officially archived as
Version 1.00 on August 17, 1987.

So this means it’s very 16bit & 32bit friendly, especially on BIG endian machines like the 68000 processor.

Luckily this older version is pretty trivial to compile, and get running.  But I was over thinking the build process and decided to strip the executable as GCC would kick out a 500kb file, which objcopy would extract a 81kb executable.  Stripping it brought the size down to a 50kb executable but it wouldn’t run in either xm6 or run68.  I ended up going in circles for a while trying to find fault in what is broken where until I manually compiled the interpreter, and omitted the strip step and suddenly had a working interpreter.

Now there is one issue, saving doesn’t work.  Something in the libc is having issues using fopen with a file to write.  Reading works perfectly fine though.  So to fix it, I went ahead and redid the save feature to use the HumanOS native _open/_write/_close functions and I’m able to now save & restore a game.

D:\proj\run68\test>run68.exe infocom.X minizork.z3
MINI-ZORK I: The Great Underground Empire
Copyright (c) 1988 Infocom, Inc. All rights reserved.
ZORK is a registered trademark of Infocom, Inc.
Release 34 / Serial number 871124

West of House
You are standing in an open field west of a white house, with a boarded front
door. You could circle the house to the north or south.
There is a small mailbox here.

West of House Score: 0/0
>restore
Filename: mz1.sav
Ok.

Living Room Score: 10/19
>inventory
You have:
A nasty knife
A rope
A sword
A brass lantern (providing light)
A brown sack
A glass bottle
The glass bottle contains:
A quantity of water
A leaflet

Living Room Score: 10/20
>

In this process I’ve also managed to build run68, and verified that it’s operating correctly, as both run68 and XM6 both failed to write to a file with fopen, and both work using the native calls.

Planetfall on a x68000

Planetfall on a x68000

I’m sure most people won’t care but I think it’s great having the ability to run a GCC generated C program in a relatively small interpreter.

If anyone cares, here is my updated cross compiler + run68 source along with tweaked Info Task Force 1.0 source.  Or a disk image that XM6 can boot up, and run some demo programs from Infocom of ages ago.

Cross compiling to i386 Linux ELF from OS X

This isn’t terribly useful for 99.9% of the people out there but I needed to do something creative on an F5.  Luckily they run a somewhat sane version of Linux.

Unfortunately I am stuck on Windows 10 right now, so installing a matching Linux distro is out of the question.  So on my OS X box, I thought I’d just build a cross compiler.  Going back to my DJGPP cross compiler, I thought I’d stick with binutils 2.9.1 and gcc 2.95.3, since they worked so well before.

Plus to flesh it out, you’ll want libc, libg++, and the appropriate Linux includes.  I took all of these from Slackware 3.3 since it’s from around that era.

So on the plus side this cross compiler + library set , will crank out static ELF executables, which makes running things on alien platforms all the better.

On the realistic side, I doubt anyone will need it, but here it is.

Clang didn’t want to build anything this old, but luckily that backported GCC-4.2 has no issues.

Cross compiling to the Sharp x68000

While looking for some stuff on the x68000, I came across this package Lydux, which features GCC setup as a cross compiler from either Windows or Linux to Human68k.

So I downloaded the Windows version, set it up according to this guide, and set on trying to build a simple EXE.  I did install CodeBlocks, but I ran into a problem while trying to build a running executable.  For some reason objcopy doesn’t work correctly unless it is in verbose mode.  I found that by accident, but much to my surprise it does work!

Hello World cross compiled from Windows to the x68000

Hello World cross compiled from Windows to the x68000

In the script for CodeBlocks, changing

oc_x = _T(“human68k-objcopy -O xfile $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE).X”);

to

oc_x = _T(“human68k-objcopy -v -O xfile $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE).X”);

did the trick, and now it’ll generate working executables.

I’ve found the emulator XM6 TypeG version 3.13 L21 the easiest to deal with as it has English translated menu’s and lets you mount a folder on your PC as a virtual drive.  This makes loading cross compiled stuff much easier.

Since finding this stuff is getting harder and harder, and that most of the xm6 forked emulators are closed source, I thought I’d at least upload what I’ve been able to find.  It’s a shame the 68030 stuff is closed off, but there isn’t anything I can do about that.  Apparently there was some feud between some dev groups.  I’m not really sure as it seems.

All my work on this is here.

WindrvXM settings

WindrvXM settings

Be sure to set the shared directory under Tools -> Options to be able to map a shared directory.  In the disks sub directory there is a HUMAN302 disk image which contains the needed device driver to map into the directory.  You can run either the 68000 or 68030 model depending on what you like more.  If you have no emulated SCSI or SASI disk, the shared directory will appear as your ‘c’ drive.  And as always the keyboard will be mapped to a Japanese keyboard, so that is why the : * = keys seem in the wrong place.

On the OS X front I went ahead and built a cross compiler.  I ran into this fun error building GCC on OS X:

Makefile:142: ../.././gcc/libgcc.mvars: No such file or directory

So yeah it turns out you really should configure/compile gcc in a separate directory from the source. Bad old habits die hard. Anyways my tool chain is here. I’m running 10.10 so I’m not sure about older versions of OS X.

OpenWatcom v2

I know what you are thinking, wouldn’t it be great if you could create MS-DOS executables directly from a Win64 desktop with no MS-DOS needed?

Well, I just found out about this unofficial Open Watcom v2 project that targets the usual suspects, allows you to compile from Win64!

Hello World!

Hello World!

Some of the features of this fork include:

  • New 2-phase build system, OW can be build by platform native C/C++ compiler or by itself
  • Code generator properly initialize pointers by DLL symbol addresses
  • DOS version of tools now support long file names (LFN) if appropriate LFN driver is loaded by DOS
  • OW is ported to 64-bit hosts (WIN64, Linux X64)
  • Librarian support X64 CPU object modules and libraries
  • RDOS 32-bit C run-time compact memory model libraries are fixed
  • Resource compiler and Resource editors support WIN64 executables
  • OW text editor is now self containing, it can be used as standalone tool without any requirements for any additional files or configuration
  • Broken C++ compiler pre-compiled header template support is fixed
  • Many C++ compiler crashes are fixed
  • Debugger has no length limit for any used environment variable

Binaries are available on sourceforge.

So how does it fare?  I thought I’d take the old Wolf4GW, and compile it with this toolset.  The first hurdle I hit was this fun feature:

  • The C++ compiler now treats warning W737, implicit conversion of pointers to integral types of same size, as an error.

Which is an integral part of wl_menu.cpp .  So this was somewhat problematic, until I just commented out that block, and while I was expecting no working keyboard, I’m able to play, and load/save games…. Even the boss key works.

Wolf4GW

Wolf4GW

So with the W737 taken care of, I have to say this thing compiles FAST.  Incredibly FAST.  If for some reason you have to build 16bit or 32bit anything, you should look at a 64bit tool chain, well assuming you have a 64bit computer by now.

If anyone want’s to build their own Wolf4GW with the newer OpenWatcom, my source drop is here.

DICE C Compiler for the Amiga

So on my last adventure through some disk corruption on my Amiga, the natural thing to do is find some kind of MD5 checksum program to then compare signatures of files being copies to ensure that they are being copied correctly.

While there were several great C compilers for the Amiga when it was a viable platform, the one left standing today is GCC.  Which is fine and all, but it is rather large, and unwieldy.  And won’t run on a computer with 2MB of RAM (In the off chance that I want to run it on the 600).  But that is when I found out that the source code (dice.com has moved!)  to old DICE compiler is available!  DICE, was originally a public domain compiler then turned commercial then finally turned freeware.  For its time it was thought as a highly capable compiler as reviewed here. Also of note is that is was written by  Matt Dillon, who later went on to DragonFLY BSD fame.

So I thought I’d try something completely different.

So after extracting the 3.15 binary distribution (which also included cross compiling from linux/i386), and following the install notes I tried to build a md5 program that I had found into an AmigaDOS binary.  And it didn’t work.  It turns out that it is missing include files related to AmigaDOS.  And I was further unable to build DICE C from within DICE C.

So after a lot of searching, I came across this, a cut down “Mini DICE” that was bundled with Amiga Shopper, meaning it has the following limitations:

  • Only small library modules are included.
  • No Bitfields
  • No floating point
  • No pragmas
  • No register variables/arguments
  • The maximun executable program size is 40K
  • Each source file can only have up to 4 procedures
MiniDice

MiniDice

Wow that is.. limiting.  But it does have several of the needed include files, and a nice setup program to get going.  At first I tried doing a full-sale overlay of the ‘3.15 binary’ version but I broke something to do with REXX and how DICE links.  So instead I just overlaid the core compiler, namely dcc, dc1, dccp, das, dlink, dmake, fdtolib & fdtopragma.

I was then finally able to compile md5.  I went ahead and started to build some of the source, and so far using a combination of dmake & vmake I was able to rebuild das, dcc, dlink, dc1 and dccp.  I went ahead and created backups of my somewhat improved dice, and dice with source code.  Some programs build fine from the command line, others you need to invoke the visual build tool.

So how is the environment?  I tried to build Dungeon (dung27s.zip) for the heck of it, but the visual makefile tool couldn’t handle a project with 33 files.  I suppose I could have made a library and gone through with some linking hell but that seemed like work.  Instead I just typed in all the C files from the command line, and compiled it that way.  Taking care of a warning and a few errors and I actually got a binary!

Dungeon on the Amiga

Dungeon on the Amiga

Even better, it runs!

AmiDevCpp

Antoni sent me a link to this project, AmiDevCpp. It is a nice little wrapped up IDE for cross compiling applications for the following platforms:

  • AmigaOS (m68k)
  • AmigaOS4 (PPC)
  • MorphOS(PPC)
  • AROS (i386, ppc and x86_64).

Naturally it doesn’t work correctly on Wine.. .Oh well, but for you Windows users out there that haven’t installed Cygwin this is an easy way to cross build stuff for the ancient Amiga platform.

Apparently he was able to rebulid the infamous aclock using this cross compiler…

Super small 64bit OS

it doesn’t do much, but it does work!.. I saw it mentioned here, and the source archive can be downloaded here.

So I went through the steps of  building a 64bit cross tool to build it.. Although Qemu won’t boot the kernel directly, and it uses GRUB which isn’t so bad but I haven’t made a transparent boot system for it just yet…  Maybe I can use a CD-ROM ISO image…

C:\temp\trunk4>build
C:\temp\trunk4>del *.o kernel.bin kernel.ld
C:\temp\trunk4>x86_64-pc-elf-cpp -Iinclude -P -C -DLINKER_SCRIPT -o kernel.ld kernel.lds
C:\temp\trunk4>x86_64-pc-elf-gcc -Iinclude -Xassembler --divide -c -o startup.o startup.S
C:\temp\trunk4>x86_64-pc-elf-gcc -Wall  -nostdlib -nodefaultlibs -mcmodel=large -Iinclude -c -o kmain.o kmain.c
kmain.c: In function 'kmain':
kmain.c:17: warning: unused variable 'n'
kmain.c:15: warning: unused variable 'str'
C:\temp\trunk4>x86_64-pc-elf-gcc -Wall  -nostdlib -nodefaultlibs -mcmodel=large -Iinclude -c -o idt.o idt.c
C:\temp\trunk4>x86_64-pc-elf-gcc -Iinclude -Xassembler --divide -c -o isr.o isr.S
C:\temp\trunk4>x86_64-pc-elf-gcc -Wall  -nostdlib -nodefaultlibs -mcmodel=large -Iinclude -c -o pic.o pic.c
C:\temp\trunk4>x86_64-pc-elf-gcc -Wall  -nostdlib -nodefaultlibs -mcmodel=large -Iinclude -c -o console.o console.c
C:\temp\trunk4>x86_64-pc-elf-ld -nodefaultlibs -z max-page-size=0x1000 -o kernel.bin -T kernel.ld startup.o kmain.o idt.o isr.o pic.o console.o
C:\temp\trunk4>x86_64-pc-elf-objdump -S kernel.bin  1>kernel.asm

The ‘warnings’ are all my fault… As I wanted a string not the 1,2,3,4…

Grub boot flags

 

And here we are in 64bit long mode!

So for the two or three people who care, my archive is here… I may move crap around, but at the same time building a 64bit cross compiler was a real chore.. More so because that x86_64-elf bare targets didn’t exist until some time around 4.3.2 which… is involved to build.