import (
"bytes"
+ "debug/elf"
+ "debug/macho"
"fmt"
"go/format"
"internal/race"
t.Run("Example1", testWith("Example", "ExampleSimple"))
t.Run("Example2", testWith("Example", "ExampleWithEmptyOutput"))
}
+
+func TestBuildmodePIE(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skipf("skipping test because buildmode=pie is not supported on gccgo")
+ }
+
+ platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
+ switch platform {
+ case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
+ "android/amd64", "android/arm", "android/arm64", "android/386":
+ case "darwin/amd64":
+ default:
+ t.Skipf("skipping test because buildmode=pie is not supported on %s", platform)
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ tg.tempFile("main.go", `package main; func main() { print("hello") }`)
+ src := tg.path("main.go")
+ obj := tg.path("main")
+ tg.run("build", "-buildmode=pie", "-o", obj, src)
+
+ switch runtime.GOOS {
+ case "linux", "android":
+ f, err := elf.Open(obj)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if f.Type != elf.ET_DYN {
+ t.Errorf("PIE type must be ET_DYN, but %s", f.Type)
+ }
+ case "darwin":
+ f, err := macho.Open(obj)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if f.Flags&macho.FlagDyldLink == 0 {
+ t.Error("PIE must have DyldLink flag, but not")
+ }
+ if f.Flags&macho.FlagPIE == 0 {
+ t.Error("PIE must have PIE flag, but not")
+ }
+ default:
+ panic("unreachable")
+ }
+
+ out, err := exec.Command(obj).CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if string(out) != "hello" {
+ t.Errorf("got %q; want %q", out, "hello")
+ }
+}
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386":
codegenArg = "-shared"
+ case "darwin/amd64":
+ codegenArg = "-shared"
default:
base.Fatalf("-buildmode=pie not supported on %s\n", platform)
}
argv = append(argv, "-Wl,-headerpad,1144")
if l.DynlinkingGo() {
argv = append(argv, "-Wl,-flat_namespace")
- } else if !SysArch.InFamily(sys.ARM64) {
+ } else if !SysArch.InFamily(sys.ARM64) && Buildmode != BuildmodePIE {
argv = append(argv, "-Wl,-no_pie")
}
case objabi.Hopenbsd:
argv = append(argv, "-Wl,-pagezero_size,4000000")
}
case BuildmodePIE:
- if UseRelro() {
- argv = append(argv, "-Wl,-z,relro")
+ // ELF.
+ if Headtype != objabi.Hdarwin {
+ if UseRelro() {
+ argv = append(argv, "-Wl,-z,relro")
+ }
+ argv = append(argv, "-pie")
}
- argv = append(argv, "-pie")
case BuildmodeCShared:
if Headtype == objabi.Hdarwin {
argv = append(argv, "-dynamiclib")
var msect *MachoSect
if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 ||
- (SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive || Buildmode == BuildmodePlugin)) ||
- (SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive || Buildmode == BuildmodePlugin))) {
+ (SysArch.Family == sys.AMD64 && Buildmode != BuildmodeExe) ||
+ (SysArch.Family == sys.ARM && Buildmode != BuildmodeExe)) {
// Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode
// complains about absolute relocs in __TEXT, so if the section is not
// executable, put it in __DATA segment.