Day 17: My Go Vet Check Was Merged đ
đ« 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:
- Github Repo: âChapter 1: A Primer on Go Assemblyâ
- Powerpoint: âx86 Programming IIâ
- Blog: âA Foray Into Go Assembly Programmingâ
- A list of âannoying aliasesâ for go compiler instructions