With further analysis, i find that it should be a Go compatibility issue to external linker (for ARM64 and MIPS64).
In Alpine and other various security hardened Linux distros, GCC toolchain enable PIE by default and user needs to explicitly pass "-no-pie" (but unrecognized by older gcc) to turn it off.
But Golang compile object file with buildmode="exe" by default and generate an abnormal executable file with invoking external linker which enable PIE by default.
Recently GCC upstream started supporting default PIE and the compatibility issue expects to appear in more Linux distros in future.
Besides previous solution of adding a new GOOS, i suggest following three solutions. Any comments?
Solution 1
Change default buildmode from "exe" to "pie" (but it will impact all platforms and os)
Solution 2
Provide a configuration for user to customize Golang default buildmode. e.g., use environment variable as below
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -214,7 +214,13 @@ func addBuildFlags(cmd *Command) {
cmd.Flag.Var((*stringsFlag)(&buildAsmflags), "asmflags", "")
cmd.Flag.Var(buildCompiler{}, "compiler", "")
- cmd.Flag.StringVar(&buildBuildmode, "buildmode", "default", "")
+
+ if bm := os.Getenv("GOBUILDMODE"); bm != "" {
+ cmd.Flag.StringVar(&buildBuildmode, "buildmode", bm, "")
+ } else {
+ cmd.Flag.StringVar(&buildBuildmode, "buildmode", "default", "")
+ }
+
cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "")
(user needs to set GOBUILDMODE="pie" for Alpine and other security hardened Linux distros)
Solution 3
Turn PIE off explicitly for "exe" buildmode by detecting the flag toolchain can recognize as below
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 366b6c0..99569b7 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -68,6 +68,9 @@ func mkEnv() []envVar {
env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
cmd = b.gxxCmd(".")
env = append(env, envVar{"CXX", cmd[0]})
+ if b.gccSupportsNoPie() {
+ env = append(env, envVar{"GOGCCNOPIE", "-no-pie"})
+ }
}
if buildContext.CgoEnabled {
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 629facd..b5c5638 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1000,6 +1000,9 @@ func (l *Link) hostlink() {
if Headtype == obj.Hdarwin {
argv = append(argv, "-Wl,-pagezero_size,4000000")
}
+ if nopieflags := os.Getenv("GOGCCNOPIE"); nopieflags != "" {
+ argv = append(argv, nopieflags)
+ }
(This solution won't impact existing Linux distros but can fix crash issue in Alpine and other distros with PIE enabled by default)