Arthur T Knackerbracket has found the following story:
GO binaries are weird, or at least, that is where this all started out. While delving into some Linux malware named Rex, I came to the realization that I might need to understand more than I wanted to. Just the prior week I had been reversing Linux Lady which was also written in GO, however it was not a stripped binary so it was pretty easy. Clearly the binary was rather large, many extra methods I didn't care about - though I really just didn't understand why. To be honest - I still haven't fully dug into the Golang code and have yet to really write much code in Go, so take this information at face value as some of it might be incorrect; this is just my experience while reversing some ELF Go binaries! If you don't want to read the whole page, or scroll to the bottom to get a link to the full repo, just go here.
-- submitted from IRC
(Score: 3, Interesting) by NCommander on Tuesday December 20 2016, @09:28PM
I worked with Go professionally at a previous job. While I dislike the language itself immesensily, the toolchain and ecosystem are beyond fucked to say the least.
Go works on the philosphy that its binaries should be completely standalone, and that libraries shouldn't exist (they've partially caved on this view, but more in a moment). Unlike almost every programming language I've encountered before, Golang only generates static binaries, and directly embeds the runtime and dependent modules right into the output. This means you do get a binary that always works everywhere (assuming you have a recent enough kernel), but intentionally attempts to avoid things like kernel vDSO modules or the C library. As such security fixes to libraries require a full rebuild of all Go modules, and the resulting binary that comes out is relatively massive.
This is compounded by the fact that library imports on Go are just git repos. The "go" tool simply grabs them with git, builds them, and directly links them into the project. As far as I can tell, this design only makes sense with monorepos used by corporations like Google, and tends to run into the problems with dependency libraries, as I've had interfaces break on me due an upstream changing something, and go helpfully updating on the fly. As part of their magic of making goroutines and such work, Go setups up a segmented stack (an unusual, but not unique choice; Ada does the same, and I believe Rust does so), but refuses to have any interactions with operating system threads. Because Go exists as a monolithic binary, C interfaces have to be directly exposed for FFI and drastically complicate the build process since you now need to get cgo into the mix. If you're dealing with a C library that heavily depends on callbacks, you're about to hit a lot of pain. Furthermore, convincing cgo to use existing headers and libraries is an exercise in frustation; I mostly ended up having to write C wrappers to get everything to work and hand massage parts of the build system at times to keep this going. As goroutines only exist as part of the userspace Go library, Go is dependent on state being kept in the "main" thread that implicately exists in all processes. As best I can tell, a pointer to a go function immediately becomes invalid the moment C code returns into Go. That means if you're dealing with C code that threads, and depends on static callbacks being available, you're fucked. My "solution" to this was simply catch the callbacks in a C handle, and then Go would simply get the data structure from C on a regular interval.
This isn't even getting into the toolchain itself, which is directly descended from the Plan 9 compiler. I can understand that the Go developers wanted to work with something they understood, and could have forgiven it, except for the fact that they refuse to provide any serious support for gccgo (which tends to lag several major behind) or LLVM. As such, getting Go to do anything that isn't directly in the box requires bending the toolchain into a pretzel, and requires a lot of serious black magic. It's quite possibly one of the most fucked up programming environments I've ever worked with. (I could write a rant in-depth on the language itself; this is just the tooling and ecosystem I'm ranting about).
Still always moving