]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go, cmd/link: build c-archive as position independent on ELF
authorIan Lance Taylor <iant@golang.org>
Thu, 16 Jun 2016 19:59:09 +0000 (12:59 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 23 Aug 2016 13:12:56 +0000 (13:12 +0000)
This permits people to use -buildmode=c-archive to produce an archive
file that can be included in a PIE or shared library.

Change-Id: Ie340ee2f08bcff4f6fd1415f7d96d51ee3a7c9a1
Reviewed-on: https://go-review.googlesource.com/24180
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
misc/cgo/testcarchive/carchive_test.go
src/cmd/go/build.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/symtab.go
src/cmd/link/internal/x86/asm.go
src/cmd/link/internal/x86/obj.go

index ab14c007a9cb5241d89083a1cd48c6765f8eefcc..14de439bcee2a269cf5e0c57ea9f4f506e99ecd6 100644 (file)
@@ -6,6 +6,7 @@ package carchive_test
 
 import (
        "bufio"
+       "debug/elf"
        "fmt"
        "io/ioutil"
        "os"
@@ -84,8 +85,13 @@ func init() {
                cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
        }
        libgodir = GOOS + "_" + GOARCH
-       if GOOS == "darwin" && (GOARCH == "arm" || GOARCH == "arm64") {
-               libgodir = GOOS + "_" + GOARCH + "_shared"
+       switch GOOS {
+       case "darwin":
+               if GOARCH == "arm" || GOARCH == "arm64" {
+                       libgodir += "_shared"
+               }
+       case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+               libgodir += "_shared"
        }
        cc = append(cc, "-I", filepath.Join("pkg", libgodir))
 
@@ -487,3 +493,71 @@ func TestExtar(t *testing.T) {
                }
        }
 }
+
+func TestPIE(t *testing.T) {
+       switch GOOS {
+       case "windows", "darwin", "plan9":
+               t.Skipf("skipping PIE test on %s", GOOS)
+       }
+
+       defer func() {
+               os.Remove("testp" + exeSuffix)
+               os.RemoveAll("pkg")
+       }()
+
+       cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
+       cmd.Env = gopathEnv
+       if out, err := cmd.CombinedOutput(); err != nil {
+               t.Logf("%s", out)
+               t.Fatal(err)
+       }
+
+       ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, "libgo.a"))
+       if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+               t.Logf("%s", out)
+               t.Fatal(err)
+       }
+
+       binArgs := append(bin, "arg1", "arg2")
+       if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
+               t.Logf("%s", out)
+               t.Fatal(err)
+       }
+
+       f, err := elf.Open("testp" + exeSuffix)
+       if err != nil {
+               t.Fatal("elf.Open failed: ", err)
+       }
+       defer f.Close()
+       if hasDynTag(t, f, elf.DT_TEXTREL) {
+               t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
+       }
+}
+
+func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
+       ds := f.SectionByType(elf.SHT_DYNAMIC)
+       if ds == nil {
+               t.Error("no SHT_DYNAMIC section")
+               return false
+       }
+       d, err := ds.Data()
+       if err != nil {
+               t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
+               return false
+       }
+       for len(d) > 0 {
+               var t elf.DynTag
+               switch f.Class {
+               case elf.ELFCLASS32:
+                       t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
+                       d = d[8:]
+               case elf.ELFCLASS64:
+                       t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
+                       d = d[16:]
+               }
+               if t == tag {
+                       return true
+               }
+       }
+       return false
+}
index 3c0b994ef24041935e97485b3a9169f553ed7dee..1c9d3b2ba20f45ec15dbd8a0c0c9c0e11b787610 100644 (file)
@@ -338,6 +338,13 @@ func buildModeInit() {
                case "darwin/arm", "darwin/arm64":
                        codegenArg = "-shared"
                default:
+                       switch goos {
+                       case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+                               // Use -shared so that the result is
+                               // suitable for inclusion in a PIE or
+                               // shared library.
+                               codegenArg = "-shared"
+                       }
                }
                exeSuffix = ".a"
                ldBuildmode = "c-archive"
index e0dd87819ad2ffbde3ca0693b8e768744111a3c1..68719a89d08cb876df089cd0fde1ecfb9b6824b5 100644 (file)
@@ -163,7 +163,7 @@ func DynlinkingGo() bool {
 // relro.
 func UseRelro() bool {
        switch Buildmode {
-       case BuildmodeCShared, BuildmodeShared, BuildmodePIE:
+       case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared, BuildmodePIE:
                return Iself
        default:
                return *FlagLinkshared
@@ -1642,7 +1642,7 @@ func stkcheck(ctxt *Link, up *Chain, depth int) int {
                // onlyctxt.Diagnose the direct caller.
                // TODO(mwhudson): actually think about this.
                if depth == 1 && s.Type != obj.SXREF && !DynlinkingGo() &&
-                       Buildmode != BuildmodePIE && Buildmode != BuildmodeCShared {
+                       Buildmode != BuildmodeCArchive && Buildmode != BuildmodePIE && Buildmode != BuildmodeCShared {
                        ctxt.Diag("call to external function %s", s.Name)
                }
                return -1
index 6a2a6d29087b218088a89f5db8b95f9eb4dedfdf..bb40282638f61161017d4c79c1ecdd620969b001 100644 (file)
@@ -155,7 +155,7 @@ func putelfsym(ctxt *Link, x *Symbol, s string, t int, addr int64, size int64, v
        if x.Type&obj.SHIDDEN != 0 {
                other = STV_HIDDEN
        }
-       if (Buildmode == BuildmodePIE || DynlinkingGo()) && SysArch.Family == sys.PPC64 && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
+       if (Buildmode == BuildmodeCArchive || Buildmode == BuildmodePIE || DynlinkingGo()) && SysArch.Family == sys.PPC64 && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
                // On ppc64 the top three bits of the st_other field indicate how
                // many instructions separate the global and local entry points. In
                // our case it is two instructions, indicated by the value 3.
@@ -362,7 +362,7 @@ func (ctxt *Link) symtab() {
        // pseudo-symbols to mark locations of type, string, and go string data.
        var symtype *Symbol
        var symtyperel *Symbol
-       if UseRelro() && (Buildmode == BuildmodeCShared || Buildmode == BuildmodePIE) {
+       if UseRelro() && (Buildmode == BuildmodeCArchive || Buildmode == BuildmodeCShared || Buildmode == BuildmodePIE) {
                s = Linklookup(ctxt, "type.*", 0)
 
                s.Type = obj.STYPE
index e7eace0781b35db14233504ac0b6d96213eaba91..63a7e1537e609c10bc13a87252a4b6c0ee8efa6c 100644 (file)
@@ -51,8 +51,19 @@ func addcall(ctxt *ld.Link, s *ld.Symbol, t *ld.Symbol) {
 }
 
 func gentext(ctxt *ld.Link) {
-       if !ld.DynlinkingGo() && ld.Buildmode != ld.BuildmodePIE && ld.Buildmode != ld.BuildmodeCShared {
-               return
+       if ld.DynlinkingGo() {
+               // We need get_pc_thunk.
+       } else {
+               switch ld.Buildmode {
+               case ld.BuildmodeCArchive:
+                       if !ld.Iself {
+                               return
+                       }
+               case ld.BuildmodePIE, ld.BuildmodeCShared:
+                       // We need get_pc_thunk.
+               default:
+                       return
+               }
        }
 
        // Generate little thunks that load the PC of the next instruction into a register.
index d356f720e09570bbd9e5c37c79e964513d442fcc..46ca62c28bf9bc898cc0368ea4ec34e34e5bc7a6 100644 (file)
@@ -85,7 +85,7 @@ func archinit(ctxt *ld.Link) {
                ld.Linkmode = ld.LinkInternal
        }
 
-       if ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE || ld.DynlinkingGo() {
+       if (ld.Buildmode == ld.BuildmodeCArchive && ld.Iself) || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE || ld.DynlinkingGo() {
                ld.Linkmode = ld.LinkExternal
                got := ld.Linklookup(ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
                got.Type = obj.SDYNIMPORT