Easy to read Golang assembly output?

golang assembly examples
go bytecode
movq golang
golang decompiler
golang rodata
go_asm h
objdump
golang simd

I'm interested in examining the x86 assembly output of the standard Go compiler to see if my code is really being converted into reasonably efficient assembly code; hopefully, by profiling and examining the assembly output, I could get a clue as to where/how I should rewrite my Go code for maximum performance. But when I examine the code using the -S flag, Go spits out a mess! I'd like two things:

  1. Is there a way to make the Go compiler dump the assembly output into a file, not just print it out on Terminal?

  2. Also, is there a way to make the Go compiler separate out the assembly code into separate functions, with labels? I know some functions may be inlined and hence not appear in the assembly code. What I'm seeing know is just a homogenous blob of assembly which is almost impossible to understand.

  1. You can redirect the output to a file like this:

    go tool 6g -S file.go > file.s
    
  2. You can disable the optimization with -N:

    go tool 6g -S -N file.go
    

Alternatively, you can use gccgo:

gccgo -S -O0 -masm=intel test.go

which will generate test.s. You can play with the -O0/1/2/3 to see the different optimizations.

A Quick Guide to Go's Assembler, The question is, given a simple Go program like this: package you may want; when it's enabled, files are decompressed only when they are read the first time. I'm interested in examining the x86 assembly output of the standard Go compiler to see if my code is really being converted into reasonably efficient assembly code; hopefully, by profiling and examining the assembly output, I could get a clue as to where/how I should rewrite my Go code for maximum p

I don't recommend using the output of -S as the Go linker can change what gets written to the object code quite a lot. It does give you some idea as to what is going on.

The go assembler output is rather non-standard too.

When I want to do this I always use objdump which will give you a nice standard assembler output.

Eg for x86 / amd64

objdump -d executable > disassembly

And for ARM (to get the register names to be the same as Go uses)

objdump -M reg-names-raw -d executable > disassembly

How to get assembly output from a small Go program? : golang, I'm interested in examining the x86 assembly output of the standard Go compiler to see if my code is really being converted into reasonably  Minimize use of assembly. We'd rather have a small amount of assembly for a 50% speedup rather than twice as much assembly for a 55% speedup. Explain the decision to place the assembly/Go boundary where it is in the commit message, and support it with benchmarks. Explain the root causes in code comments or commit messages.

Run go tool objdump on the resulting executable file.

To restrict the output to interesting functions, use its -s option.

Go Tools: The Compiler, The Go compiler is at the heart of Go's build process, taking code and generating executables from that code. Go's compiler is May 10, 2019 · 6 min read. The Go I'm keeping it simple because the output tends to be very verbose. // main.go UniDoc's UniPDF (formerly unidoc) is a PDF library for Go (golang) with capabilities for creating and reading, processing PDF files. The library is written and supported by FoxyUtils.com, where the library is used to power many of its services. $ unipdf -h

To dump the output to file:

go tool objdump EXECUTABLE_FILE > ASSEMBLY_FILE

If you want to include the source Go code (assuming you have a working golang setup, and you built the executable yourself):

go tool objdump -S EXECUTABLE_FILE

To make the output even easier to look at I use a small hacky wrapper that produces the following (in a nutshell, it colorizes instructions that alter the control flow -blue for jumps, green for call/return, red for traps, violet for padding- and adds new lines after unconditional control flow jumps):

If you use the wrapper above you will likely want to use the -R switch when piping to less (or by adding it to the environment, e.g. in .bashrc: export LESS="$LESS -R"):

go-objdump EXECUTABLE_FILE | less -R

Alternatively, there is godbolt.org that has probably the most readable output and allows you to switch between compilers (gc, gccgo) and versions very easily.

Compiler Explorer, Compiler Explorer is an interactive online compiler which shows the assembly output of compiled C++, Rust, Go (and many more) code. Read populates the given byte slice with data and returns the number of bytes populated and an error value. It returns an io.EOF error when the stream ends. The example code creates a strings.Reader and consumes its output 8 bytes at a time.

I had problems with the other answers as the assembly produced provided much more information than I wanted and still not enough details. Let me explain: it provided the assembly for all libraries imported by go internally and did not provide the lines of where my code was (my code was all at the bottom of the file)

Here is what I found from the official docs:

$ GOOS=linux GOARCH=amd64 go tool compile -S x.go # or: go build -gcflags -S x.go

File:

package main

func main() {
    println(3)
}

Produces:

--- prog list "main" ---
0000 (x.go:3) TEXT    main+0(SB),$8-0
0001 (x.go:3) FUNCDATA $0,gcargs·0+0(SB)
0002 (x.go:3) FUNCDATA $1,gclocals·0+0(SB)
0003 (x.go:4) MOVQ    $3,(SP)
0004 (x.go:4) PCDATA  $0,$8
0005 (x.go:4) CALL    ,runtime.printint+0(SB)
0006 (x.go:4) PCDATA  $0,$-1
0007 (x.go:4) PCDATA  $0,$0
0008 (x.go:4) CALL    ,runtime.printnl+0(SB)
0009 (x.go:4) PCDATA  $0,$-1
0010 (x.go:5) RET     ,

So what I did was basically:

go tool compile -S hello.go > hello.s

and it got the result I wanted!

go-internals/README.md at master · teh-cmc/go-internals · GitHub, The Go assembler then uses this pseudo-assembly output in order to generate the main one being how easy it makes porting Go to new architectures. while we're at it, understand the general idea of what they do and why do they do it. No, you can't, but it is easy to provide an assembly implementation of just one function by using the go compiler. There is no need to use "Import C" to use assembly. Take a look at an example from the math library:

WebAssembly · golang/go Wiki · GitHub, If you're new to WebAssembly read the Getting Started section, watch some of the Go The .wasm file extension will make it easier to serve it over HTTP with the correct open the JavaScript debug console, and you should see the output. I'm interested in examining the x86 assembly output of the standard Go compiler to see if my code is really being converted into reasonably efficient assembly code; hopefully, by profiling and examining the assembly output, I could get a clue as to where/how I should rewrite my Go code for maximum performance.

3 Ways For Getting The Assembly Code Of Go Programs , Although their output formats may be somewhat different, they are all assembly code which is easy to read and can help us understand the  The meaning of this assembly is that you collect the binary in one image, then transfer it as an artifact to the next — small one, where it starts. This whole process is described in one Dockerfile.

A Foray Into Go Assembly Programming · Scott Mansfield, Apr 21, 2017 · 12 minute read · 8 Comments · GoASM In this case, a divide by 3 is equivalent to multiplying by 0x55555556 and then taking the top half of the output. This was easy as it was pretty straightforward to change the Java code into Go. Function names in Go assembly files start with a middot character ( · ). It's quite easy to think about and quite productive. However, if it progresses to truly parallel hardware, it's quite hard to balance the load well. Everything goes at the speed of the slowest pipeline stage. Geometric decomposition - Dividing the data up into separate regions that can be processed independently (or without too much

Comments
  • 1) What about using > or whatever your command shell supports for redirecting the output of a command to a file?
  • Also, your approach to profiling by looking at the assembly code may not be the most productive one. Have you looked at the profiling tools available for Go code? (e.g. blog.golang.org/profiling-go-programs)
  • I agree with you, assembly output needs some improvement. The problem is that the Go compiler does not generate actual assembly. It generates something that looks a lot like assembly but contains a lot of pseudo-instructions that will be expanded by the linker. Only after linking is done, actual assembly is produced (and immediately assembled).
  • Also, have a look at how the Plan 9 assembler works. The reference implementation of Go uses this assembler.
  • PS: I'm looking for something similar to the GCC command: -fverbose-asm
  • go build -gcflags -S test.go > test.s should work, too (according to golang.org/doc/asm)
  • go tool comile -S file.go > file.S since go1.5
  • @IvanBlack Your comment deserves a top-level response.
  • You might find the Godbolt compiler explorer useful for color highlighting to map source lines to asm. godbolt.org/g/yQ4gbQ has output for a simple function with both gc1.10.1 and gccgo 7.2.
  • That is a really nice tool