aboutsummaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2018-01-23 04:44:12 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-01-23 04:44:12 +0000
commit38ad6f8a440f7594b9cea5fb999078035ee36a57 (patch)
tree2499e11d4df673826314f3f14158f8467d4a42db /libgo
parentf991f1022c6254678cc61304ecd1e0fba0ac79db (diff)
downloadgcc-38ad6f8a440f7594b9cea5fb999078035ee36a57.zip
gcc-38ad6f8a440f7594b9cea5fb999078035ee36a57.tar.gz
gcc-38ad6f8a440f7594b9cea5fb999078035ee36a57.tar.bz2
cmd/go: buildid support for AIX archives.
Reviewed-on: https://go-review.googlesource.com/88935 From-SVN: r256971
Diffstat (limited to 'libgo')
-rw-r--r--libgo/go/cmd/go/internal/work/buildid.go37
-rw-r--r--libgo/go/cmd/go/internal/work/exec.go10
-rw-r--r--libgo/go/cmd/internal/buildid/buildid.go83
3 files changed, 130 insertions, 0 deletions
diff --git a/libgo/go/cmd/go/internal/work/buildid.go b/libgo/go/cmd/go/internal/work/buildid.go
index 39ca20e..e2ae850 100644
--- a/libgo/go/cmd/go/internal/work/buildid.go
+++ b/libgo/go/cmd/go/internal/work/buildid.go
@@ -330,6 +330,43 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
return sfile, nil
}
+// gccgoBuildIDXCOFFFile creates an assembler file that records the
+// action's build ID in a CSECT (AIX linker deletes CSECTs that are
+// not referenced in the output file).
+func (b *Builder) gccgoBuildIDXCOFFFile(a *Action) (string, error) {
+ sfile := a.Objdir + "_buildid.s"
+
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "\t.csect .go.buildid[XO]\n")
+ fmt.Fprintf(&buf, "\t.byte ")
+ for i := 0; i < len(a.buildID); i++ {
+ if i > 0 {
+ if i%8 == 0 {
+ fmt.Fprintf(&buf, "\n\t.byte ")
+ } else {
+ fmt.Fprintf(&buf, ",")
+ }
+ }
+ fmt.Fprintf(&buf, "%#02x", a.buildID[i])
+ }
+ fmt.Fprintf(&buf, "\n")
+
+ if cfg.BuildN || cfg.BuildX {
+ for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) {
+ b.Showcmd("", "echo '%s' >> %s", line, sfile)
+ }
+ if cfg.BuildN {
+ return sfile, nil
+ }
+ }
+
+ if err := ioutil.WriteFile(sfile, buf.Bytes(), 0666); err != nil {
+ return "", err
+ }
+
+ return sfile, nil
+}
+
// buildID returns the build ID found in the given file.
// If no build ID is found, buildID returns the content hash of the file.
func (b *Builder) buildID(file string) string {
diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go
index c2704c4..edd2694 100644
--- a/libgo/go/cmd/go/internal/work/exec.go
+++ b/libgo/go/cmd/go/internal/work/exec.go
@@ -637,6 +637,16 @@ func (b *Builder) build(a *Action) (err error) {
return err
}
objects = append(objects, ofiles...)
+ case "aix":
+ asmfile, err := b.gccgoBuildIDXCOFFFile(a)
+ if err != nil {
+ return err
+ }
+ ofiles, err := BuildToolchain.asm(b, a, []string{asmfile})
+ if err != nil {
+ return err
+ }
+ objects = append(objects, ofiles...)
}
}
diff --git a/libgo/go/cmd/internal/buildid/buildid.go b/libgo/go/cmd/internal/buildid/buildid.go
index fa3d7f3..41e6c77 100644
--- a/libgo/go/cmd/internal/buildid/buildid.go
+++ b/libgo/go/cmd/internal/buildid/buildid.go
@@ -7,6 +7,7 @@ package buildid
import (
"bytes"
"debug/elf"
+ "debug/xcoff"
"fmt"
"io"
"os"
@@ -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")