So the first request for a port of Madness has arrived, and that request was to port it to OS X. Not quite what I expected, as my money would have been on a request to port it to Windows. However, I was happy that is wasn’t, as porting to OS X would surely be easier as it is a BSD derivative.
I’m not an OS X expert, but I knew that being a BSD derivative, the calling convention was different. Linux system calls are more like DOS in that they take their arguments in registers. BSD, and hence OS X, follow the more traditional UNIX convention of passing arguments by pushing them onto the stack. Since I encapsulated all of the hardware/operating system functionality in a module called hardware.s (which I’m now thinking should be renamed platform.s), adding the pushes before making system calls should be trivial.
So I fired up my trusty Hackintosh system that I created a year or so ago (a Lenovo T530 running OS X Lion), cloned the madness repository and executed make. I didn’t expect it to work, but I certainly didn’t expect to see the errors it was complaining about; errors about unknown pseudo-ops like .equ, .ifdef, and .bss. I thought perhaps it wasn’t using the GNU assembler, so I checked the version:
$ as -v
Apple Inc version cctools-822, GNU assembler version 1.38
Version 1.38? That seems pretty old, as I recall binutils being version 2.x for some time now. Just to be sure, I checked the version on my Linux box:
$ as -v
GNU assembler version 2.22 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.
Sure enough, it is version 2.22.
I also have OS X Mavericks running on my Hackintosh, so I fired it up to see what version it is using. To my surprise, it is the same old version. A little digging around revealed that it is well known that Apple’s GNU toolchain is quite old, and the reason for it seems to be it is being replaced with LLVM. So there will be no new versions of the GNU toolchain shipped with OS X. With this revelation, I tried using llvm-gcc-42 – same errors. I imagine that llvm-gcc probably uses /usr/bin/as anyway.
Next thing to try was clang. With clang, the original errors disappeared, but were replaced by complaints of the unknown directives .rept and endr. Checking my clang version:
$ clang -v
Apple clang version 3.1 (tags/Apple/clang-318.0.58) (based on LLVM 3.1svn)
and cross-checking that with what’s out there, I find clang is outdated too. Rather than upgrade to the latest & greatest version, I opted to try the next version – clang 3.2. After downloading and installing clang 3.2, my preprocessor problems disappeared and in their place were a few assembler errors that I could deal with.
After working out all the assembler errors, adding push instructions before making system calls, and changing a few system call numbers that differed between OS X and Linux, I had Madness running on OS X. However, the timer, which is central to the game, was not working.
I tried to debug the problem on OS X, but ran into problems with gdb – there were no symbols in the binary for it to use. None of the usual command-line options seemed to work with clang. So I switched to the lldb debugger. This debugger had symbols, but no line information, so I couldn’t set breakpoints on line numbers and so had to resort to addresses. After messing with lldb for a while, I decided the tools on OS X weren’t up to par and figured I’d have an easier time porting to BSD first, and then from BSD to OS X. That way I could shake out all the bugs on BSD (where I have the latest GNU toolchain), and after I had it working there I could try porting it to OS X again. So the OS X port was put on hold in favor of a BSD port!
Update: As mentioned elsewhere in my blog, I have recently setup OS X to run as a KVM guest under Linux. In doing that, I have learned that installing Xcode and then the command-line tools for Xcode gives a working tool chain in which I can compile Madness. I have tried this with both Mountain Lion and Mavericks. This means there is no reason to install clang manually. I haven’t tried the debugger yet, but will post back when I do.