Commit faafcc60 authored by Clément Chigot's avatar Clément Chigot Committed by Ian Lance Taylor

cmd: allow build with gccgo on AIX

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: 's avatarIan Lance Taylor <iant@golang.org>
parent 0ad332d8
......@@ -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"
......
......@@ -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
}
......
......@@ -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)
......
......@@ -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")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment