So I had this itch that I wanted to make a Go program compile to eBPF and be able to load that program in the Linux kernel by use of bpftool.

As I say in github.com/miekg/ebpf

eBPF in C? What am I, a farmer?

After much reading about eBPF and thinking about how that would work from Go, I figured that would involve writing a Go compiler.

So I could:

  1. hack the official Go compiler and (try to) add a eBPF target (which would probably never be added as an official target because of all the constraints eBPF has).

  2. create a complete stand-alone and new compiler that parses Go code and emits eBPF binary in an ELF object.

  3. find something else that already does (2) and works with constraint backends.

I thought a while about doing (2), but that just seemed A LOT OF WORK.

While searching I found TinyGo which seems to do everything I want it to do, except of course output eBPF bytecode.

So TinyGo it is! For now at least, (2) is still an option – although a distant one.

First Steps

After forking and building TinyGo I need it to recognize (e)BPF (going to drop the ’e’ going forward) as a valid target.

Turns out this is relative easy: just create a target/bpf.json file with the “correct” values, recompile tinygo (make), and voila:

% ./build/tinygo targets | grep bpf
bpf

The top of target/bpf.json now looks as:

{
	"llvm-target":   "bpf",
	"cpu":           "generic",
	"features":      "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext",
	"build-tags":    ["tinygo.bpf"],
	"goos":          "linux",
    ...

The llvm-target might actually be correct, the rest is still BS (well GOOS might be OK too). But my main goal here is to make TinyGo output (via llvm) BPF bytecode and take it from there.