đŸ«– Mood: Drinking tea on the front porch looking over my garden at sunset.

đŸŽ” Soundtrack: silence

📚 Reading Github Issues

Read at least 20 new github issues this morning nothing super exciting.

🐈‍⬛ My Go Vet Check Was Merged!!!

My third - and by far largest - contribution has been merged! Yay! There are now 6 “meows” in golang/tools. I couldn’t be prouder.

đŸ§¶ Updates on My Go Fuzz Issue

This morning I found that my go fuzz issue had been closed given that it was a duplicate of this one. Oops! I did search before I opened it. I swear!

I ended up changing my commit to point to this issue and resubmitted it. I also added this comment to my PR:

Hello 👋

I originally open this code for this issue golang/go#48657, which ended up being duplicate/subset of golang/go#48129.

Some open thoughts I have on this change:

  • I am not in love with how I changed the function signature for minimizeBytes. Your feedback on this is welcome.
  • I wasn’t sure if I should minimize symbols to “$”. Maybe that is too American centric? “=” is another option.
  • In issue golang/go#48129 Russ Cox suggested a different algorithm for minimizing. If you would prefer that algorithm I am happy to change this.

đŸȘĄ The Go Compiler

As someone who has never had to think about compiling beyond remembering to set GOOS, I have been shocked my the number of github issues about the compiler. This is really out of my realm. Definitely not something covered in my CS 101 class or my 9 week bootcamp. Well, this is the perfect time to learn! My goal is to move compiling from the “it’s ✹~m@G!c~✹” part of my brain to the “oh, I know the broad strokes of how that works” part of my brain.

đŸŽ„ I started by watching “GopherCon 2020: Jaana Dogan - Debugging Code Generation in Go”

(Side note: I’ve really enjoyed the time I’ve had to go through past GopherCon conference talks during this sabbatical! A few years ago, I remember thinking “A conference about a language?? That sounds so boring” and now I’m like “Wow, I wish I had the time to watch every talk from GopherCon 2020 and I can’t wait until it’s safe to do conferences in person again”. The times have changed.)

From Jaana’s talk I learned about a lot of commands I can run to inspect my code:

  • go build flags
    • -a forces a rebuild, even if it’s in the cache. This would’ve been nice when I was testing my go vet check. Because I would change comments, but that isn’t enough to bust the cache even though my tests were testing comments.
    • -x shows tooling invocations
    • -n dry run: shows tooling invocations, but doesn’t run them
    • -work stops the $WORK directory from being cleaned up so you can inspect the temporary dir and all the temporary files made during compilation
  • go build gc (go compiler) flags
    • -gcflags="-S" generates the intermediary assembly (not the platform specific assembly)
    • -gcflags="-N" disables optimizations
    • -gcflags="-l" disables inlining
    • -gcflags="-l -l" extra inlining
    • -gcflags="-m" see what is escaping to the heap
    • -gcflags="-m=2" see what is escaping to the heap with more detail
  • GOSSAFUNC=FUNCTION_NAME go build -a makes a really cool html page that you can open in your browser and you can interact with all of the different compilation stages

Jaana’s talk was good, but it assumed more knowledge about assembly and compiliers than I currently have. So then I watched this “x86 Assembly Crash Course”.

I can’t say everything is clear, but I think the best next step is just to dive in, run some of these commands, and try to understand them myself.

I made this little file called sum.go:

1 package main
2
3 import "fmt"
4
5 func main() {
6   sum := 1 + 1
7   fmt.Println(sum)
8 }

And then I looked at the assembly. This code has been edited to fit nicely and to only contain the bits that (I think) I am interested in.

$ go build -gcflags="-S"


(sum.go:5)	TEXT	"".main(SB), ABIInternal, $64-0
(sum.go:5)	CMPQ	SP, 16(R14)  <--- compare the SP register with ??
(sum.go:5)	PCDATA	$0, $-2      <--- something for garbage collecting
(sum.go:5)	JLS	95           <--- jump if lower or same (unsigned)
(sum.go:5)	PCDATA	$0, $-1      <--- something for garbage collecting
(sum.go:5)	SUBQ	$64, SP      <--- XOR 68bytes backwards
(sum.go:5)	MOVQ	BP, 56(SP)   <--- 64bit value move
(sum.go:5)	LEAQ	56(SP), BP   <--- computes new address of the SP and stores it in BP
(sum.go:5)	FUNCDATA	$0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) <--- gc stuff
(sum.go:5)	FUNCDATA	$1, gclocals·f207267fbf96a0178e8758c6e3e0ce28(SB) <--- gc stuff
(sum.go:5)	FUNCDATA	$2, "".main.stkobj(SB)  <--- gc stuff
(sum.go:7)	MOVL	$2, AX                          <--- move $2 into AX
(sum.go:7)	PCDATA	$1, $0                          <--- gc stuff
(sum.go:7)	CALL	runtime.convT64(SB)             <--- call the convT64 function
(sum.go:7)	MOVUPS	X15, ""..autotmp_11+40(SP)      <--- ??
(sum.go:7)	LEAQ	type.int(SB), CX                <--- load effective address from int to CX
(sum.go:7)	MOVQ	CX, ""..autotmp_11+40(SP)       <--- move quadword (64 bits) from CX to ...?
(sum.go:7)	MOVQ	AX, ""..autotmp_11+48(SP)       <--- move quadword (64 bits) from AX to ...?
(sum.go:8)	MOVQ	56(SP), BP                      <--- move qw from ?? to BP
(sum.go:8)	ADDQ	$64, SP                         <--- add $64 and SP together, store in $64 (I think?)
(sum.go:8)	RET                                     <--- return from procedure
(sum.go:8)	NOP                                     <--- no op. ???
(sum.go:5)	PCDATA	$1, $-1                         <--- gc stuff
(sum.go:5)	PCDATA	$0, $-2                         <--- gc stuff
(sum.go:5)	NOP                                     <--- no op???
(sum.go:5)	CALL	runtime.morestack_noctxt(SB)    <--- call the function morestack_noctxt with SB
(sum.go:5)	PCDATA	$0, $-1                         <--- gc stuff
(sum.go:5)	JMP	0                               <--- jump???

I started looking up each of the instructions meant and adding them in comments. I want to go through this and understand it better, but I ran out of time today.

While doing this I came across the official go doc “A Quick Guide to Go’s Assembler”. Wow. It would be generous if I said that I understood 10% of that. Just in case I started thinking I understood anything here are some choice quotes that set me straight:

  • “The assembler works on the semi-abstract form, so when you see an instruction like MOV what the toolchain actually generates for that operation might not be a move instruction at all, perhaps a clear or load. Or it might correspond exactly to the machine instruction with that name.”
  • “Constant expressions in the assembler are parsed using Go’s operator precedence, not the C-like precedence of the original. Thus 3&1«2 is 4, not 0—it parses as (3&1)«2 not 3&(1«2).”
  • “There are four predeclared symbols that refer to pseudo-registers.”

đŸ˜”â€đŸ’« So all I know is that nothing is as it seems.

Also while I was researching these instructions, I found the following interesting resources that I want to keep in my back pocket: