back

by stevekemp·15d ago·view on hn ↗
I wrote a lisp compiler recently, and that involved generating assembly language.

My output is linux/amd64 assembly language which is compiled by nasm. I don't link to glibc, so I had to implement my "print int", "print string", and similar primitives in raw assembly.

I successfully implemented a stop&copy garbage collector, and other interfaces to the OS such as reading command-line arguments, environmental variables, and so on. All in assembly. Though my compiler is written in golang the runtime, and all supporting functions have to be in assembly to make sure that the binaries it produced are static.

(I wrote a lisp interpreter which can be compiled, and which can be used to run itself, so I got an indirect REPL.)

1 comments
An efficient concurrent garbage collector would be something I would buy a book for. (In fact I have one GC book on my bookshelf).

But assembly? I'm not sure, honestly. Architectures change, and you can easily converge to good code by talking to an LLM.

May I ask why you didn't use LLVM as a target?

I wanted something standalone I could implement and understand from the ground-up, that's why I did everything myself, rather than using LLVM.

In the future I might try to repeat the process with QBE, or similar, but LLVM is a big dependency and a bit of a moving target too.

I'm only writing toy languages for fun, and for local problem solving. I have no delusions of grandeur and expect that for every compiler/language I come up with I'll have one user at the most, possibly two.