Brian Robert Callahan

academic, developer, with an eye towards a brighter techno-social life


I ported the new Hare compiler to OpenBSD

As soon as I finished writing up the previous blog post, I was made aware of the announcement of a new programming language named Hare. It was pointed out to me that Hare released with Linux and FreeBSD support. We'll just have to port it to OpenBSD. Let's get to work.

Compiler and runtime: A language in two parts

Hare comes in two repositories: a compiler and a runtime. This blog post will only deal with porting the compiler; we'll port the runtime in a follow-up post.

Getting started

First I cloned the compiler and copied the rt/+freebsd directory to a new rt/+openbsd directory and did the rote renaming from FreeBSD to OpenBSD in the new directory. Next, I had to modify rt/+openbsd/errno.ha to reflect the reality in OpenBSD. The file to look at is here and it really is just a rote making the changes to match. Then I had to do the same thing for rt/+openbsd/syscallno.ha which is just again a rote making the changes from here. I then edited rt/configure to copy the FreeBSD section into an OpenBSD section and make the rote changes inside the new OpenBSD section.

Now I could begin building the Hare compiler. The instructions said to create a new build directory and from there run ../configure so that's what I did. Hare uses QBE for its backend. Good thing I recently imported a QBE port.

The first build errors

Hare is not a particularly big compiler so there are only a handful of files to build. I did run into some build errors though: the Hare compiler uses a mktemp function that does not match the mktemp(3) prototype. So that caused an error. The fix is simple—all you have to do is rename all the occurances of mktemp in the Hare code. I renamed it to emktemp since I'm not yet worried about selecting the final new name right now.

I then had several occurances of printf format string warnings but because -Werror was turned on from upstream, these broke the build. Fortunately, clang will tell you what you need to change the offending format strings to, so I just listened to clang. I think that OpenBSD differs from Linux and FreeBSD here (think: the difference between %ld and %lld), but it is all legal according to the C spec, so this might be something upstream will need to smooth over.

And hey the build finished. The instructions say you can run make check to run the test suite. So I did that.

And all the tests failed.

Teaching Hare about OpenBSD ELF binaries

OpenBSD has some special requirements for its ELF binaries. All OpenBSD binaries need a .note.openbsd.ident section with a couple of magic numbers and the string "OpenBSD". I may be misremembering, but I believe that this is an artifact of when OpenBSD had Linux emulation so the kernel would know if an ELF binary was a Linux or OpenBSD binary. The Linux emulation was removed but the special identifier stayed. We actually saw the special code needed for this all the way back in our SnakeQR game. I added this code into the assembly code for the _start function.

I then needed to teach the Hare linker script to recognize and keep the new .note.openbsd.ident section.

Now I can rebuild and retest.

And the tests still failed.

Using gdb for the last clue

Opening a test binary with GDB and forcing the debugger to break at the very first instruction with starti, I noticed that the memory location for the first instruction kept changing each time I reran the program. Looks like I forgot to tell the linker that it needs to include the -nopie flag.

Another quick rebuild and retest and all the tests passed.

Shipping a patch

I sent a patch with all these changes to the mailing list. It won't go in as-is, due to the printf format string mismatches between OpenBSD and the others, and maybe a few other tweaks.


This was a very quick and simple porting job. But there is always something to learn. Now that the compiler is finished, I'll work on the standard library and then work on riscv64 and arm64 support. Stay tuned!