]> Cypherpunks repositories - gostls13.git/commitdiff
cmd: allow build with gccgo on AIX
authorClément Chigot <clement.chigot@atos.net>
Mon, 29 Oct 2018 12:39:53 +0000 (13:39 +0100)
committerIan Lance Taylor <iant@golang.org>
Wed, 31 Oct 2018 00:17:00 +0000 (00:17 +0000)
This commit adapts cmd/internal/buildid and cmd/go to allow the use of
gccgo on AIX.
Buildid is supported only for AIX archives.

Change-Id: I14c790a8994ae8d2ee629d8751e04189c30ffd94
Reviewed-on: https://go-review.googlesource.com/c/145417
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/go/internal/work/buildid.go
src/cmd/go/internal/work/exec.go
src/cmd/go/internal/work/gccgo.go
src/cmd/internal/buildid/buildid.go

index af3183ae9a061fc656c9225248309404e61badc5..a6cfb50558ba53ee15b5f5e632b02bbe971eccb4 100644 (file)
@@ -322,13 +322,16 @@ func assemblerIsGas() bool {
        }
 }
 
-// gccgoBuildIDELFFile creates an assembler file that records the
-// action's build ID in an SHF_EXCLUDE section.
-func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
+// gccgoBuildIDFile creates an assembler file that records the
+// action's build ID in an SHF_EXCLUDE section for ELF files or
+// in a CSECT in XCOFF files.
+func (b *Builder) gccgoBuildIDFile(a *Action) (string, error) {
        sfile := a.Objdir + "_buildid.s"
 
        var buf bytes.Buffer
-       if cfg.Goos != "solaris" || assemblerIsGas() {
+       if cfg.Goos == "aix" {
+               fmt.Fprintf(&buf, "\t.csect .go.buildid[XO]\n")
+       } else if cfg.Goos != "solaris" || assemblerIsGas() {
                fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n")
        } else if cfg.Goarch == "sparc" || cfg.Goarch == "sparc64" {
                fmt.Fprintf(&buf, "\t"+`.section ".go.buildid",#exclude`+"\n")
@@ -347,7 +350,7 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
                fmt.Fprintf(&buf, "%#02x", a.buildID[i])
        }
        fmt.Fprintf(&buf, "\n")
-       if cfg.Goos != "solaris" {
+       if cfg.Goos != "solaris" && cfg.Goos != "aix" {
                secType := "@progbits"
                if cfg.Goarch == "arm" {
                        secType = "%progbits"
index 99a500f11ff75826ace1adf07e7b545c4ed2eedf..d9c59aab80061ff503f6b7f0c0acc2f3a745c375 100644 (file)
@@ -699,8 +699,8 @@ func (b *Builder) build(a *Action) (err error) {
        // This is read by readGccgoArchive in cmd/internal/buildid/buildid.go.
        if a.buildID != "" && cfg.BuildToolchainName == "gccgo" {
                switch cfg.Goos {
-               case "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
-                       asmfile, err := b.gccgoBuildIDELFFile(a)
+               case "aix", "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+                       asmfile, err := b.gccgoBuildIDFile(a)
                        if err != nil {
                                return err
                        }
@@ -2297,6 +2297,10 @@ func (b *Builder) gccArchArgs() []string {
                return []string{"-mabi=64"}
        case "mips", "mipsle":
                return []string{"-mabi=32", "-march=mips32"}
+       case "ppc64":
+               if cfg.Goos == "aix" {
+                       return []string{"-maix64"}
+               }
        }
        return nil
 }
index 91daf529d4111a574bead39ce036de30638f85e1..ca3be4fd364e1471cae8ee1da2e50331af5ff363 100644 (file)
@@ -186,7 +186,15 @@ func (gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string)
        for _, f := range ofiles {
                absOfiles = append(absOfiles, mkAbs(objdir, f))
        }
-       return b.run(a, p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objdir, afile), absOfiles)
+       var arArgs string
+       if cfg.Goos == "aix" && cfg.Goarch == "ppc64" {
+               // AIX puts both 32-bit and 64-bit objects in the same archive.
+               // Tell the AIX "ar" command to only care about 64-bit objects.
+               // AIX "ar" command does not know D option.
+               arArgs = "-X64"
+       }
+
+       return b.run(a, p.Dir, p.ImportPath, nil, "ar", arArgs, "rc", mkAbs(objdir, afile), absOfiles)
 }
 
 func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error {
@@ -342,17 +350,24 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
                }
        }
 
-       ldflags = append(ldflags, "-Wl,--whole-archive")
+       wholeArchive := []string{"-Wl,--whole-archive"}
+       noWholeArchive := []string{"-Wl,--no-whole-archive"}
+       if cfg.Goos == "aix" {
+               wholeArchive = nil
+               noWholeArchive = nil
+       }
+       ldflags = append(ldflags, wholeArchive...)
        ldflags = append(ldflags, afiles...)
-       ldflags = append(ldflags, "-Wl,--no-whole-archive")
+       ldflags = append(ldflags, noWholeArchive...)
 
        ldflags = append(ldflags, cgoldflags...)
        ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
        if root.Package != nil {
                ldflags = append(ldflags, root.Package.CgoLDFLAGS...)
        }
-
-       ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)")
+       if cfg.Goos != "aix" {
+               ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)")
+       }
 
        if root.buildID != "" {
                // On systems that normally use gold or the GNU linker,
@@ -363,11 +378,17 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
                }
        }
 
+       var rLibPath string
+       if cfg.Goos == "aix" {
+               rLibPath = "-Wl,-blibpath="
+       } else {
+               rLibPath = "-Wl,-rpath="
+       }
        for _, shlib := range shlibs {
                ldflags = append(
                        ldflags,
                        "-L"+filepath.Dir(shlib),
-                       "-Wl,-rpath="+filepath.Dir(shlib),
+                       rLibPath+filepath.Dir(shlib),
                        "-l"+strings.TrimSuffix(
                                strings.TrimPrefix(filepath.Base(shlib), "lib"),
                                ".so"))
@@ -412,7 +433,10 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
        case "c-shared":
                ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc")
        case "shared":
-               ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
+               if cfg.Goos != "aix" {
+                       ldflags = append(ldflags, "-zdefs")
+               }
+               ldflags = append(ldflags, "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
 
        default:
                base.Fatalf("-buildmode=%s not supported for gccgo", buildmode)
index fa3d7f37ec60d8b51423e862d9ea46fd145029f8..8205f696eb15df5b12131890bff84ac5c503d6a9 100644 (file)
@@ -6,6 +6,7 @@ package buildid
 
 import (
        "bytes"
+       "cmd/internal/xcoff"
        "debug/elf"
        "fmt"
        "io"
@@ -40,6 +41,9 @@ func ReadFile(name string) (id string, err error) {
                return "", err
        }
        if string(buf) != "!<arch>\n" {
+               if string(buf) == "<bigaf>\n" {
+                       return readGccgoBigArchive(name, f)
+               }
                return readBinary(name, f)
        }
 
@@ -157,6 +161,85 @@ func readGccgoArchive(name string, f *os.File) (string, error) {
        }
 }
 
+// readGccgoBigArchive tries to parse the archive as an AIX big
+// archive file, and fetch the build ID from the _buildid.o entry.
+// The _buildid.o entry is written by (*Builder).gccgoBuildIDXCOFFFile
+// in cmd/go/internal/work/exec.go.
+func readGccgoBigArchive(name string, f *os.File) (string, error) {
+       bad := func() (string, error) {
+               return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+       }
+
+       // Read fixed-length header.
+       if _, err := f.Seek(0, io.SeekStart); err != nil {
+               return "", err
+       }
+       var flhdr [128]byte
+       if _, err := io.ReadFull(f, flhdr[:]); err != nil {
+               return "", err
+       }
+       // Read first member offset.
+       offStr := strings.TrimSpace(string(flhdr[68:88]))
+       off, err := strconv.ParseInt(offStr, 10, 64)
+       if err != nil {
+               return bad()
+       }
+       for {
+               if off == 0 {
+                       // No more entries, no build ID.
+                       return "", nil
+               }
+               if _, err := f.Seek(off, io.SeekStart); err != nil {
+                       return "", err
+               }
+               // Read member header.
+               var hdr [112]byte
+               if _, err := io.ReadFull(f, hdr[:]); err != nil {
+                       return "", err
+               }
+               // Read member name length.
+               namLenStr := strings.TrimSpace(string(hdr[108:112]))
+               namLen, err := strconv.ParseInt(namLenStr, 10, 32)
+               if err != nil {
+                       return bad()
+               }
+               if namLen == 10 {
+                       var nam [10]byte
+                       if _, err := io.ReadFull(f, nam[:]); err != nil {
+                               return "", err
+                       }
+                       if string(nam[:]) == "_buildid.o" {
+                               sizeStr := strings.TrimSpace(string(hdr[0:20]))
+                               size, err := strconv.ParseInt(sizeStr, 10, 64)
+                               if err != nil {
+                                       return bad()
+                               }
+                               off += int64(len(hdr)) + namLen + 2
+                               if off&1 != 0 {
+                                       off++
+                               }
+                               sr := io.NewSectionReader(f, off, size)
+                               x, err := xcoff.NewFile(sr)
+                               if err != nil {
+                                       return bad()
+                               }
+                               data := x.CSect(".go.buildid")
+                               if data == nil {
+                                       return bad()
+                               }
+                               return string(data), nil
+                       }
+               }
+
+               // Read next member offset.
+               offStr = strings.TrimSpace(string(hdr[20:40]))
+               off, err = strconv.ParseInt(offStr, 10, 64)
+               if err != nil {
+                       return bad()
+               }
+       }
+}
+
 var (
        goBuildPrefix = []byte("\xff Go build ID: \"")
        goBuildEnd    = []byte("\"\n \xff")