I’ve spent the last month or so trying to port SPITBOL to Apple’s OSX.
What I thought would be a simple port — since the Linux x32 and x64 port was solid — turned out to be more daunting.
OSX is now 64-bits by default, and uses a different object format (macho) than does Linux (elf).
The main problem I’ve run into is that in 64-bits the storage model is different, so that code and data must use what is called RIP-addressing, where RIP stands for Relative to Instruction Pointer.
The first problem I ran into was a crash of NASM, the assembler I’ve been using.
Once the folks at NASM fixed that, I was unable to get even the simplest program working in RIP-mode for 64-bit OSX.
I then realized — I wish I had thought of this sooner — that OSX might support 32-bit mode.
Indeed it does. So I tried to build 32-bit SPITBOL using NASM.
This also gave problems, mainly in that it generated bad refs for the first three of so globals defined in m.s. I tried to get around this by moving their declaration to C code, but even after doing that, SPITBOL crashed.
So I have decided to convert the Minimal code generator to target GAS (the GNU assembler) and not NASM. This also involves converting the approximately 1500 lines of assembler needed to link the SPITBOL compiler to the runtime code written in C from NASM to GAS.
I’m in the midst of this, and it’s going well so far, so I’m hopeful the port will get done.
As part of the conversion from NASM to GAS, I’ve learned that GAS is less powerful when it comes to macros and substitutions. For example, in NASM, in 64-bit mode, I can write “%define WA RCX” to map the Minimal register WA to the machine register RCX. For 32-bits I can write “%define WA ECX.”
But I can’t do this in GAS, and so I wrote a program that, given the word size, maps the Minimal register names in upper-case to the corresponding hardware registers:
* rename Minimal registers to x86_64 registers according to word size for x86_64 prefix = (eq(host(0),32) "%e", "%r") rmap = table(20) rmap['XL'] = 'si'; rmap['XR'] = 'di'; rmap['XS'] = 'sp'; rmap['XT'] = 'si' rmap['WA'] = 'cx'; rmap['WB'] = 'bx'; rmap['WC'] = 'dx'; rmap['W0'] = 'ax' rmap['IA'] = 'bp' rpat = 'IA' | ('X' any('LRST')) | ('W' any('ABC0')) next line = input :f(end) loop line rpat . reg = prefix rmap[reg] :s(loop) output = line :(next) end
Being able to write code such as this, in a short time (it took about twenty minutes to write and debug) is why it is worth the long slog of implementation and porting.
It’s just such damn fun to write code in SPITBOL.