-
-
Notifications
You must be signed in to change notification settings - Fork 602
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some dynamically linked Golang executables crash on OSv #1141
Comments
The paragraph
Suggests that Linux has a special way to run a static executable. It doesn't just run a "main()" function normally like a normal function, but rather run some sort of entry point specified in the ELF in a special way (I have to say, I don't know or don't remember any of the details). I am guessing that in this case, Linux passes argv and argc on the stack (the above code suggests offset 16 and 24 on the stack, probably there is something else before?), instead of using the normal C ABI (e.g., using registers). To check if this is true you can look at the Linux source where it does this, or in the C compiler's crt0.s or whatever it is called nowadays which is used to bootstrap a static executable. Or maybe you can find some documentation on this online. If my guess above is correct (I don't know if it is...), you will need to modify OSv to jump to the static executable's entry point after setting the stack as it expects. |
I wonder if this commit from the static elf branch from 7 years ago is related. What is interesting, all httpserver executables built with options that make it crash on OSv seem to be dynamically linked per |
All of these types of golang executables - both statically and dynamically linked should work fine after recently adding support for statically linked executables. |
As I was researching the issue #1137, I have identified that some dynamically linked Golang executables crash. It seems that depending on parameters used with
go build
slightly different ELF is generated. The article found by @nyh - https://www.arp242.net/static-go.html - provides some interesting insight as to why some of these differences exist. But the devil lies in details.I have conducted somewhat extensive experiments by trying to build the
golang-pie-example
andgolang-pie-httpserver
with variousgo build
parameters using two versions of the Go toolchain - newer 1.12.6 and older 1.15.8. And here is what I have found:The
golang-pie-example
works fine on OSv when built with the following build commands:go build -buildmode=pie -ldflags "-linkmode external" -o hello-external-pie hello.go
go build -buildmode=exe -ldflags "-linkmode external" -o hello-external-exe hello.go
go build -buildmode=pie -o hello-pie hello.go
With both with 1.12.6 and 1.15.8 the
go build -buildmode=exe -o hello-exe hello.go
command (theexe
is the default), the statically linked position-dependant ELF is built which does NOT work on OSv (hopefully, once we implement #1137, #1138, #1139 and #1140 it will work fine). What is interesting the newer Golang 1.15.8 toolchain produces statically linked position-independent executable (PIE) (or dependent?) when built withgo build -buildmode=pie -o hello-pie hello.go
(unlike 1.12.6):and OSv crashes like so:
The fact OSv is reporting missing 158 syscall -
arch_prctl
- further proves it is a statically linked executable.The
golang-pie-httpserver
works fine on OSv (except for what is described in the issue #1047) when built with the following build commands:go build -buildmode=pie -ldflags "-linkmode external" -o httpserver-external-pie httpserver.go
go build -buildmode=exe -ldflags "-linkmode external" -o httpserver-external-exe httpserver.go
go build -buildmode=pie -o httpserver-pie httpserver.go
Now unlike
golang-pie-example
, the binaries produced by other build commands differ in type (the fact that httpserver uses networking- see the article - is the reason):The crash of
httpserver-exe
built with 1.12.6 looks like so:The crash of
httpserver-exe
built with 1.15.8 looks like so:The crash of
httpserver-pie
built with 1.15.8 looks like so:As one can see all 3 crashes look very similar and have something to do with how argv/args is passed to the binary vs what it expects.
Here is relevant Golang code for the 2nd and 3rd crash:
It looks like both
argv
andargc
are passed on the stack?There is also this relevant code fragment with comments in
/usr/lib/golang/src/runtime/asm_amd64.s
:The text was updated successfully, but these errors were encountered: