diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 6c6d551e79..ee20a89d86 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -2711,6 +2711,10 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions // libffi. ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive") + if b.gccSupportsNoPie() { + ldflags = append(ldflags, "-no-pie") + } + // We are creating an object file, so we don't want a build ID. ldflags = b.disableBuildID(ldflags) @@ -2902,6 +2906,36 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { return a } +// On systems with PIE (position independent executables) enabled by default, +// -no-pie must be passed when doing a partial link with -Wl,-r. But -no-pie is +// not supported by all compilers. +func (b *builder) gccSupportsNoPie() bool { + if goos != "linux" { + // On some BSD platforms, error messages from the + // compiler make it to the console despite cmd.Std* + // all being nil. As -no-pie is only required on linux + // systems so far, we only test there. + return false + } + src := filepath.Join(b.work, "trivial.c") + if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil { + return false + } + cmdArgs := b.gccCmd(b.work) + cmdArgs = append(cmdArgs, "-no-pie", "-c", "trivial.c") + if buildN || buildX { + b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs)) + if buildN { + return false + } + } + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) + cmd.Dir = b.work + cmd.Env = envForDir(cmd.Dir, os.Environ()) + err := cmd.Run() + return err == nil +} + // gccArchArgs returns arguments to pass to gcc based on the architecture. func (b *builder) gccArchArgs() []string { switch goarch { @@ -3158,6 +3192,10 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi } ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs) + if b.gccSupportsNoPie() { + ldflags = append(ldflags, "-no-pie") + } + // We are creating an object file, so we don't want a build ID. ldflags = b.disableBuildID(ldflags)