Sep 25, 2025
Mistyrt is a work in progress statically linked C runtime library written in ANSI C. Its goal is to be a more modern take on a C runtime library and abstract away most platform-specific concerns from users. It’s inspired by the Hare and Go standard libraries, and hopes to bring some of what makes them great to C.
Mistyrt is still just little. I’ve been developing it in my free time starting on Linux for x86_64 and learning as I go. Currently, it’s not capable of much more than basic I/O, but it’s getting there. I’ve decided that I want to focus on fleshing out the rt module responsible for the really platform specific stuff like syscalls and initialization, so I can focus on the higher-level modules without having to worry so much about what rt can do yet.
However, before I do this, I want to make sure that the rt module is set up in a way that can easily work with different platforms, and at the moment, Linux on x86_64 is the only supported target, so I’ve decided to port the current capabilities of mistyrt to AArch64. This way I can structure the project in a way that makes sense for multiple architectures before making anything that might be a little difficult to restructure later.
First I have to move some of the old code around. Architecture dependent code
is scattered all over despite my naive attempts at separating what I thought
would and wouldn’t be architecture-dependant. I split rt/linux/ into
the subdirectories rt/linux/x86_64/ and rt/linux/aarch64/. I initially didn’t
want to add another layer of directories here, but it’s become clear that this
will quickly become a mess if I ever need to add more architectures.
Next up, I need to be able to call main and make syscalls on AArch64. This is
fairly straightforward and works similarly to x86_64, but we do need to be
able to conditionally include the rt header and compile the correct sources
depending on the architecture in use. To include the correct header, I’ve
added an rt.h to both rt/linux/x86_64/ and rt/linux/aarch64/. The rt.h in
rt/linux/ uses an #ifdef to determine the architecture in use and include
the correct header. As for compiling the correct sources, this is something
that I think should be handled by the build system, so I’ll come back to this
later.
Next we need to implement functions for the syscalls already in use by the x86_64 rt module in the AArch64 module. All of these should work the same as they do in x86_64, with the exception of open, which has been replaced by only the openat syscall.
The syscall numbers do not match up between architectures, but besides that
there’s no reason to duplicate many of the syscall functions, as these two
platforms typically use the same arguments and return values. For now, I’ll
keep most of the existing syscalls in rt/linux/syscalls.c and include the
syscall numbers headers in the platform specific rt configurations, so when
including rt/linux/rt.h, you get the correct numbers for your platform. This
will almost definitely need restructuring if I ever implement 32-bit support,
but we don’t need to worry about that yet. The open syscall gets moved to
rt/linux/x86_64/syscalls.c all alone for now :(
Now with everything in place, most of mistyrt should now work for AArch64!
Let’s compile the hello world example. Using this command in the example
directory
aarch64-none-elf-gcc -I../include/ -std=c89 -pedantic -Wall -Wextra \
-ffreestanding -static -nostdinc -nostdlib -o bin/helloworld \
helloworld.c ../src/io/write.c ../src/io/print.c ../src/rt/linux/*.c \
../src/rt/linux/aarch64/*.s ../src/mem/*.c
it compiles! There is now an AArch64 binary in the example/bin/ directory.
When I try to execute this on my system, I of course get an error because I’m
on an x86_64 laptop. For most testing, it’s probably best to use something
like QEMU to emulate AArch64 on my development machine, but just for fun here,
I’m going to copy it over to my Raspberry Pi to see it execute natively.
Now with the binary copied over to the Raspberry Pi, we can finally execute it and see it print the hello world message!
segmentation fault
oops :/
I compile it again now with debug symbols. GDB reveals that the error is in the _start function, a silly mistake on my part caused the crash. Now after compiling and executing again we get
Hello, world!
Yay! Mistyrt is now mostly working on AArch64. This example avoids anything that uses the open syscall, so for full feature parity with x86_64, we must implement the openat syscall to use with the io_open() function.
Fortunately, although AArch64 does not have an open syscall, x86_64 does have an openat syscall! This means openat can be used for both architectures' io_open() implementations. The call to rt_open() can simply be replaced with rt_openat(), with the first argument set to a macro defined in rt for the special value -100, that tells the openat syscall to behave much like a standard open syscall.
With this implemented, plus a Makefile variable to indicate the architecture to compile for; AArch64 should now have full feature parity with x86_64, of course it’s hard to say without any tests yet.
So now with AArch64 support out of the way, what’s next? Well there’s one more major thing I want to do before I start working on an exhaustive rt module for Linux. Bring mistyrt to another OS. Right now, that OS is, naively, Windows on x86_64, a platform I know close to nothing about when it comes to its low-level workings, and I don’t really know where to look for information on those things.
I want mistyrt to support Windows, and being such a different system from Linux, I think it’s best to go there next if I want to build a robust structure. Like I said, I know nothing at all about Windows, so maybe I’ll have to pivot to Plan-9 if I want to get this done in a reasonable time frame :-)
Aside from this, I want to figure out a better system for including mistyrt in other codebases. The way I’ve set it up right now isn’t the most elegant and has more overhead than I’d like for users. I’ll have to do some research here to see if there’s a better way.
Before moving on to fleshing out the higher level modules, I also want to get some tests going, and this will likely come with the rt changes. I think I’ll do this with a simple “mistytest” library to write tests using mistyrt.
Thank you for reading! This is my brand new blog where I plan to write more updates like this along with anything else I feel like writing about. If you’re interested, please consider dropping me off in your RSS reader :3
If you have any comments, feedback, questions, or resources I might find useful (pls send any resources for learning Windows stuff), I can be reached on the fediverse at eeriera@cyberplace.social or by email at eerieraccoon@posteo.com. The source code, mailing list, and issue tracker for mistyrt are available on my sr.ht.