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

cmd/link, runtime: allow external linking for aix/ppc64

This commit adds external linking in cmd/link for aix/ppc64.
As relocations on .text data aren't possible on AIX, Segrelrodata is
used to move all these datas to .data section.

Change-Id: I4d1361c1fc9290e11e6f5560864460c76551dbeb
Reviewed-on: https://go-review.googlesource.com/c/go/+/164003
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 0ff0df8b
...@@ -247,7 +247,7 @@ func determineLinkMode(ctxt *Link) { ...@@ -247,7 +247,7 @@ func determineLinkMode(ctxt *Link) {
} }
ctxt.LinkMode = LinkInternal ctxt.LinkMode = LinkInternal
case "1": case "1":
if objabi.GOARCH == "ppc64" { if objabi.GOARCH == "ppc64" && objabi.GOOS != "aix" {
Exitf("external linking requested via GO_EXTLINK_ENABLED but not supported for %s/ppc64", objabi.GOOS) Exitf("external linking requested via GO_EXTLINK_ENABLED but not supported for %s/ppc64", objabi.GOOS)
} }
ctxt.LinkMode = LinkExternal ctxt.LinkMode = LinkExternal
...@@ -261,7 +261,7 @@ func determineLinkMode(ctxt *Link) { ...@@ -261,7 +261,7 @@ func determineLinkMode(ctxt *Link) {
} else { } else {
ctxt.LinkMode = LinkInternal ctxt.LinkMode = LinkInternal
} }
if objabi.GOARCH == "ppc64" && ctxt.LinkMode == LinkExternal { if objabi.GOARCH == "ppc64" && objabi.GOOS != "aix" && ctxt.LinkMode == LinkExternal {
Exitf("external linking is not supported for %s/ppc64", objabi.GOOS) Exitf("external linking is not supported for %s/ppc64", objabi.GOOS)
} }
} }
...@@ -270,7 +270,7 @@ func determineLinkMode(ctxt *Link) { ...@@ -270,7 +270,7 @@ func determineLinkMode(ctxt *Link) {
Exitf("internal linking requested but external linking required: %s", reason) Exitf("internal linking requested but external linking required: %s", reason)
} }
case LinkExternal: case LinkExternal:
if objabi.GOARCH == "ppc64" { if objabi.GOARCH == "ppc64" && objabi.GOOS != "aix" {
Exitf("external linking not supported for %s/ppc64", objabi.GOOS) Exitf("external linking not supported for %s/ppc64", objabi.GOOS)
} }
} }
......
...@@ -308,6 +308,8 @@ func relocsym(ctxt *Link, s *sym.Symbol) { ...@@ -308,6 +308,8 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
} }
} else if ctxt.HeadType == objabi.Hwindows { } else if ctxt.HeadType == objabi.Hwindows {
// nothing to do // nothing to do
} else if ctxt.HeadType == objabi.Haix {
o = Symaddr(r.Sym) + r.Add
} else { } else {
Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, ctxt.HeadType) Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, ctxt.HeadType)
} }
...@@ -1400,7 +1402,7 @@ func (ctxt *Link) dodata() { ...@@ -1400,7 +1402,7 @@ func (ctxt *Link) dodata() {
if len(data[sym.STLSBSS]) > 0 { if len(data[sym.STLSBSS]) > 0 {
var sect *sym.Section var sect *sym.Section
if ctxt.IsELF && (ctxt.LinkMode == LinkExternal || !*FlagD) { if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && (ctxt.LinkMode == LinkExternal || !*FlagD) {
sect = addsection(ctxt.Arch, &Segdata, ".tbss", 06) sect = addsection(ctxt.Arch, &Segdata, ".tbss", 06)
sect.Align = int32(ctxt.Arch.PtrSize) sect.Align = int32(ctxt.Arch.PtrSize)
sect.Vaddr = 0 sect.Vaddr = 0
...@@ -1538,7 +1540,7 @@ func (ctxt *Link) dodata() { ...@@ -1538,7 +1540,7 @@ func (ctxt *Link) dodata() {
if ctxt.UseRelro() { if ctxt.UseRelro() {
addrelrosection = func(suffix string) *sym.Section { addrelrosection = func(suffix string) *sym.Section {
seg := &Segrelrodata seg := &Segrelrodata
if ctxt.LinkMode == LinkExternal { if ctxt.LinkMode == LinkExternal && ctxt.HeadType != objabi.Haix {
// Using a separate segment with an external // Using a separate segment with an external
// linker results in some programs moving // linker results in some programs moving
// their data sections unexpectedly, which // their data sections unexpectedly, which
...@@ -2046,6 +2048,10 @@ func (ctxt *Link) address() []*sym.Segment { ...@@ -2046,6 +2048,10 @@ func (ctxt *Link) address() []*sym.Segment {
// align to page boundary so as not to mix // align to page boundary so as not to mix
// rodata, rel-ro data, and executable text. // rodata, rel-ro data, and executable text.
va = uint64(Rnd(int64(va), int64(*FlagRound))) va = uint64(Rnd(int64(va), int64(*FlagRound)))
if ctxt.HeadType == objabi.Haix {
// Relro data are inside data segment on AIX.
va += uint64(XCOFFDATABASE) - uint64(XCOFFTEXTBASE)
}
order = append(order, &Segrelrodata) order = append(order, &Segrelrodata)
Segrelrodata.Rwx = 06 Segrelrodata.Rwx = 06
...@@ -2060,9 +2066,10 @@ func (ctxt *Link) address() []*sym.Segment { ...@@ -2060,9 +2066,10 @@ func (ctxt *Link) address() []*sym.Segment {
} }
va = uint64(Rnd(int64(va), int64(*FlagRound))) va = uint64(Rnd(int64(va), int64(*FlagRound)))
if ctxt.HeadType == objabi.Haix { if ctxt.HeadType == objabi.Haix && len(Segrelrodata.Sections) == 0 {
// Data sections are moved to an unreachable segment // Data sections are moved to an unreachable segment
// to ensure that they are position-independent. // to ensure that they are position-independent.
// Already done if relro sections exist.
va += uint64(XCOFFDATABASE) - uint64(XCOFFTEXTBASE) va += uint64(XCOFFDATABASE) - uint64(XCOFFTEXTBASE)
} }
order = append(order, &Segdata) order = append(order, &Segdata)
...@@ -2073,11 +2080,11 @@ func (ctxt *Link) address() []*sym.Segment { ...@@ -2073,11 +2080,11 @@ func (ctxt *Link) address() []*sym.Segment {
var bss *sym.Section var bss *sym.Section
var noptrbss *sym.Section var noptrbss *sym.Section
for i, s := range Segdata.Sections { for i, s := range Segdata.Sections {
if ctxt.IsELF && s.Name == ".tbss" { if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && s.Name == ".tbss" {
continue continue
} }
vlen := int64(s.Length) vlen := int64(s.Length)
if i+1 < len(Segdata.Sections) && !(ctxt.IsELF && Segdata.Sections[i+1].Name == ".tbss") { if i+1 < len(Segdata.Sections) && !((ctxt.IsELF || ctxt.HeadType == objabi.Haix) && Segdata.Sections[i+1].Name == ".tbss") {
vlen = int64(Segdata.Sections[i+1].Vaddr - s.Vaddr) vlen = int64(Segdata.Sections[i+1].Vaddr - s.Vaddr)
} }
s.Vaddr = va s.Vaddr = va
......
...@@ -1683,6 +1683,7 @@ func dwarfEnabled(ctxt *Link) bool { ...@@ -1683,6 +1683,7 @@ func dwarfEnabled(ctxt *Link) bool {
} }
if ctxt.LinkMode == LinkExternal { if ctxt.LinkMode == LinkExternal {
// TODO(aix): enable DWARF
switch { switch {
case ctxt.IsELF: case ctxt.IsELF:
case ctxt.HeadType == objabi.Hdarwin: case ctxt.HeadType == objabi.Hdarwin:
......
...@@ -133,6 +133,7 @@ type Arch struct { ...@@ -133,6 +133,7 @@ type Arch struct {
Gentext func(*Link) Gentext func(*Link)
Machoreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool Machoreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
PEreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool PEreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
Xcoffreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
// TLSIEtoLE converts a TLS Initial Executable relocation to // TLSIEtoLE converts a TLS Initial Executable relocation to
// a TLS Local Executable relocation. // a TLS Local Executable relocation.
...@@ -179,7 +180,7 @@ func (ctxt *Link) UseRelro() bool { ...@@ -179,7 +180,7 @@ func (ctxt *Link) UseRelro() bool {
case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePIE, BuildModePlugin: case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePIE, BuildModePlugin:
return ctxt.IsELF return ctxt.IsELF
default: default:
return ctxt.linkShared return ctxt.linkShared || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal)
} }
} }
...@@ -405,7 +406,7 @@ func (ctxt *Link) loadlib() { ...@@ -405,7 +406,7 @@ func (ctxt *Link) loadlib() {
*FlagTextAddr = 0 *FlagTextAddr = 0
} }
if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 { if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && objabi.GOOS != "aix" {
toc := ctxt.Syms.Lookup(".TOC.", 0) toc := ctxt.Syms.Lookup(".TOC.", 0)
toc.Type = sym.SDYNIMPORT toc.Type = sym.SDYNIMPORT
} }
...@@ -1145,6 +1146,11 @@ func (ctxt *Link) hostlink() { ...@@ -1145,6 +1146,11 @@ func (ctxt *Link) hostlink() {
} else { } else {
argv = append(argv, "-mconsole") argv = append(argv, "-mconsole")
} }
case objabi.Haix:
argv = append(argv, "-pthread")
// prevent ld to reorder .text functions to keep the same
// first/last functions for moduledata.
argv = append(argv, "-Wl,-bnoobjreorder")
} }
switch ctxt.BuildMode { switch ctxt.BuildMode {
...@@ -1493,7 +1499,7 @@ func hostlinkArchArgs(arch *sys.Arch) []string { ...@@ -1493,7 +1499,7 @@ func hostlinkArchArgs(arch *sys.Arch) []string {
switch arch.Family { switch arch.Family {
case sys.I386: case sys.I386:
return []string{"-m32"} return []string{"-m32"}
case sys.AMD64, sys.PPC64, sys.S390X: case sys.AMD64, sys.S390X:
return []string{"-m64"} return []string{"-m64"}
case sys.ARM: case sys.ARM:
return []string{"-marm"} return []string{"-marm"}
...@@ -1503,6 +1509,13 @@ func hostlinkArchArgs(arch *sys.Arch) []string { ...@@ -1503,6 +1509,13 @@ func hostlinkArchArgs(arch *sys.Arch) []string {
return []string{"-mabi=64"} return []string{"-mabi=64"}
case sys.MIPS: case sys.MIPS:
return []string{"-mabi=32"} return []string{"-mabi=32"}
case sys.PPC64:
if objabi.GOOS == "aix" {
return []string{"-maix64"}
} else {
return []string{"-m64"}
}
} }
return nil return nil
} }
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"cmd/link/internal/sym" "cmd/link/internal/sym"
"encoding/binary" "encoding/binary"
"math/bits" "math/bits"
"sort"
"strings" "strings"
) )
...@@ -153,6 +154,7 @@ const ( ...@@ -153,6 +154,7 @@ const (
LDHDRSZ_32 = 32 LDHDRSZ_32 = 32
LDHDRSZ_64 = 56 LDHDRSZ_64 = 56
LDSYMSZ_64 = 24 LDSYMSZ_64 = 24
RELSZ_64 = 14
) )
// Type representing all XCOFF symbols. // Type representing all XCOFF symbols.
...@@ -362,6 +364,31 @@ type xcoffLoaderReloc struct { ...@@ -362,6 +364,31 @@ type xcoffLoaderReloc struct {
const ( const (
XCOFF_R_POS = 0x00 // A(sym) Positive Relocation XCOFF_R_POS = 0x00 // A(sym) Positive Relocation
XCOFF_R_NEG = 0x01 // -A(sym) Negative Relocation
XCOFF_R_REL = 0x02 // A(sym-*) Relative to self
XCOFF_R_TOC = 0x03 // A(sym-TOC) Relative to TOC
XCOFF_R_TRL = 0x12 // A(sym-TOC) TOC Relative indirect load.
XCOFF_R_TRLA = 0x13 // A(sym-TOC) TOC Rel load address. modifiable inst
XCOFF_R_GL = 0x05 // A(external TOC of sym) Global Linkage
XCOFF_R_TCL = 0x06 // A(local TOC of sym) Local object TOC address
XCOFF_R_RL = 0x0C // A(sym) Pos indirect load. modifiable instruction
XCOFF_R_RLA = 0x0D // A(sym) Pos Load Address. modifiable instruction
XCOFF_R_REF = 0x0F // AL0(sym) Non relocating ref. No garbage collect
XCOFF_R_BA = 0x08 // A(sym) Branch absolute. Cannot modify instruction
XCOFF_R_RBA = 0x18 // A(sym) Branch absolute. modifiable instruction
XCOFF_R_BR = 0x0A // A(sym-*) Branch rel to self. non modifiable
XCOFF_R_RBR = 0x1A // A(sym-*) Branch rel to self. modifiable instr
XCOFF_R_TLS = 0x20 // General-dynamic reference to TLS symbol
XCOFF_R_TLS_IE = 0x21 // Initial-exec reference to TLS symbol
XCOFF_R_TLS_LD = 0x22 // Local-dynamic reference to TLS symbol
XCOFF_R_TLS_LE = 0x23 // Local-exec reference to TLS symbol
XCOFF_R_TLSM = 0x24 // Module reference to TLS symbol
XCOFF_R_TLSML = 0x25 // Module reference to local (own) module
XCOFF_R_TOCU = 0x30 // Relative to TOC - high order bits
XCOFF_R_TOCL = 0x31 // Relative to TOC - low order bits
) )
type XcoffLdStr64 struct { type XcoffLdStr64 struct {
...@@ -374,6 +401,9 @@ type xcoffFile struct { ...@@ -374,6 +401,9 @@ type xcoffFile struct {
xfhdr XcoffFileHdr64 xfhdr XcoffFileHdr64
xahdr XcoffAoutHdr64 xahdr XcoffAoutHdr64
sections []*XcoffScnHdr64 sections []*XcoffScnHdr64
sectText *XcoffScnHdr64
sectData *XcoffScnHdr64
sectBss *XcoffScnHdr64
stringTable xcoffStringTable stringTable xcoffStringTable
sectNameToScnum map[string]int16 sectNameToScnum map[string]int16
loaderSize uint64 loaderSize uint64
...@@ -487,10 +517,15 @@ func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 { ...@@ -487,10 +517,15 @@ func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 {
if sect.Name == ".noptrbss" || sect.Name == ".bss" { if sect.Name == ".noptrbss" || sect.Name == ".bss" {
return f.sectNameToScnum[".bss"] return f.sectNameToScnum[".bss"]
} }
if sect.Name == ".tbss" {
return f.sectNameToScnum[".tbss"]
}
Errorf(nil, "unknown XCOFF segment data section: %s", sect.Name) Errorf(nil, "unknown XCOFF segment data section: %s", sect.Name)
case &Segdwarf: case &Segdwarf:
name, _ := xcoffGetDwarfSubtype(sect.Name) name, _ := xcoffGetDwarfSubtype(sect.Name)
return f.sectNameToScnum[name] return f.sectNameToScnum[name]
case &Segrelrodata:
return f.sectNameToScnum[".data"]
} }
Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name) Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name)
return -1 return -1
...@@ -746,6 +781,7 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym { ...@@ -746,6 +781,7 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
s.Nsclass = C_HIDEXT s.Nsclass = C_HIDEXT
} }
x.Dynid = int32(xfile.symbolCount)
syms = append(syms, s) syms = append(syms, s)
// Update current csect size // Update current csect size
...@@ -801,6 +837,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, ...@@ -801,6 +837,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
Ntype: SYM_TYPE_FUNC, Ntype: SYM_TYPE_FUNC,
Nnumaux: 1, Nnumaux: 1,
} }
x.Dynid = int32(xfile.symbolCount)
syms = append(syms, s) syms = append(syms, s)
size := uint64(x.Size) size := uint64(x.Size)
...@@ -835,6 +872,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, ...@@ -835,6 +872,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
s.Nsclass = C_HIDEXT s.Nsclass = C_HIDEXT
} }
x.Dynid = int32(xfile.symbolCount)
syms = append(syms, s) syms = append(syms, s)
// Create auxiliary entry // Create auxiliary entry
...@@ -849,9 +887,18 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, ...@@ -849,9 +887,18 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
Xscnlenlo: uint32(size & 0xFFFFFFFF), Xscnlenlo: uint32(size & 0xFFFFFFFF),
Xscnlenhi: uint32(size >> 32), Xscnlenhi: uint32(size >> 32),
} }
// Read only data
if x.Type >= sym.STYPE && x.Type <= sym.SPCLNTAB { if x.Type >= sym.STYPE && x.Type <= sym.SPCLNTAB {
if ctxt.LinkMode == LinkExternal && strings.HasPrefix(x.Sect.Name, ".data.rel.ro") {
// During external linking, read-only datas with relocation
// must be in .data.
a4.Xsmclas = XMC_RW
} else {
// Read only data
a4.Xsmclas = XMC_RO a4.Xsmclas = XMC_RO
}
} else if x.Type == sym.SDATA && strings.HasPrefix(x.Name, "TOC.") && ctxt.LinkMode == LinkExternal {
a4.Xsmclas = XMC_TC
} else if x.Name == "TOC" { } else if x.Name == "TOC" {
a4.Xsmclas = XMC_TC0 a4.Xsmclas = XMC_TC0
} else { } else {
...@@ -876,6 +923,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, ...@@ -876,6 +923,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
Noffset: uint32(xfile.stringTable.add(str)), Noffset: uint32(xfile.stringTable.add(str)),
Nnumaux: 1, Nnumaux: 1,
} }
x.Dynid = int32(xfile.symbolCount)
syms = append(syms, s) syms = append(syms, s)
a4 := &XcoffAuxCSect64{ a4 := &XcoffAuxCSect64{
...@@ -971,7 +1019,7 @@ func (f *xcoffFile) genDynSym(ctxt *Link) { ...@@ -971,7 +1019,7 @@ func (f *xcoffFile) genDynSym(ctxt *Link) {
func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) { func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) {
// Check that library name is given. // Check that library name is given.
// Pattern is already checked when compiling. // Pattern is already checked when compiling.
if s.Dynimplib() == "" { if ctxt.LinkMode == LinkInternal && s.Dynimplib() == "" {
Errorf(s, "imported symbol must have a given library") Errorf(s, "imported symbol must have a given library")
} }
...@@ -1008,6 +1056,9 @@ func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) { ...@@ -1008,6 +1056,9 @@ func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) {
// Xcoffadddynrel adds a dynamic relocation in a XCOFF file. // Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
// This relocation will be made by the loader. // This relocation will be made by the loader.
func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool { func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool {
if ctxt.LinkMode == LinkExternal {
return true
}
if s.Type <= sym.SPCLNTAB { if s.Type <= sym.SPCLNTAB {
Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name) Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name)
return false return false
...@@ -1072,6 +1123,7 @@ func (ctxt *Link) doxcoff() { ...@@ -1072,6 +1123,7 @@ func (ctxt *Link) doxcoff() {
toc := ctxt.Syms.Lookup("TOC", 0) toc := ctxt.Syms.Lookup("TOC", 0)
toc.Type = sym.SXCOFFTOC toc.Type = sym.SXCOFFTOC
toc.Attr |= sym.AttrReachable toc.Attr |= sym.AttrReachable
toc.Attr |= sym.AttrVisibilityHidden
// XCOFF does not allow relocations of data symbol address to a text symbol. // XCOFF does not allow relocations of data symbol address to a text symbol.
// Such case occurs when a RODATA symbol retrieves a data symbol address. // Such case occurs when a RODATA symbol retrieves a data symbol address.
...@@ -1110,6 +1162,7 @@ func (ctxt *Link) doxcoff() { ...@@ -1110,6 +1162,7 @@ func (ctxt *Link) doxcoff() {
if !ep.Attr.Reachable() { if !ep.Attr.Reachable() {
Exitf("wrong entry point") Exitf("wrong entry point")
} }
xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{ xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{
sym: ep, sym: ep,
smtype: XTY_ENT | XTY_SD, smtype: XTY_ENT | XTY_SD,
...@@ -1123,6 +1176,12 @@ func (ctxt *Link) doxcoff() { ...@@ -1123,6 +1176,12 @@ func (ctxt *Link) doxcoff() {
s.Type = sym.SXCOFFTOC s.Type = sym.SXCOFFTOC
} }
} }
if ctxt.LinkMode == LinkExternal {
// Change main name to match __start code.
main := ctxt.Syms.ROLookup("_main", 0)
main.Name = ".main"
}
} }
// Loader section // Loader section
...@@ -1337,7 +1396,7 @@ func (f *xcoffFile) writeFileHeader(ctxt *Link) { ...@@ -1337,7 +1396,7 @@ func (f *xcoffFile) writeFileHeader(ctxt *Link) {
f.xfhdr.Fnsyms = int32(f.symbolCount) f.xfhdr.Fnsyms = int32(f.symbolCount)
} }
if ctxt.BuildMode == BuildModeExe { if ctxt.BuildMode == BuildModeExe && ctxt.LinkMode == LinkInternal {
f.xfhdr.Fopthdr = AOUTHSZ_EXEC64 f.xfhdr.Fopthdr = AOUTHSZ_EXEC64
f.xfhdr.Fflags = F_EXEC f.xfhdr.Fflags = F_EXEC
...@@ -1383,15 +1442,41 @@ func Asmbxcoff(ctxt *Link, fileoff int64) { ...@@ -1383,15 +1442,41 @@ func Asmbxcoff(ctxt *Link, fileoff int64) {
xfile.xahdr.Otextstart = s.Svaddr xfile.xahdr.Otextstart = s.Svaddr
xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"] xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"]
xfile.xahdr.Otsize = s.Ssize xfile.xahdr.Otsize = s.Ssize
xfile.sectText = s
s = xfile.addSection(".data", Segdata.Vaddr, Segdata.Filelen, Segdata.Fileoff, STYP_DATA) segdataVaddr := Segdata.Vaddr
segdataFilelen := Segdata.Filelen
segdataFileoff := Segdata.Fileoff
segbssFilelen := Segdata.Length - Segdata.Filelen
if len(Segrelrodata.Sections) > 0 {
// Merge relro segment to data segment as
// relro data are inside data segment on AIX.
segdataVaddr = Segrelrodata.Vaddr
segdataFileoff = Segrelrodata.Fileoff
segdataFilelen = Segdata.Vaddr + Segdata.Filelen - Segrelrodata.Vaddr
}
s = xfile.addSection(".data", segdataVaddr, segdataFilelen, segdataFileoff, STYP_DATA)
xfile.xahdr.Odatastart = s.Svaddr xfile.xahdr.Odatastart = s.Svaddr
xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"] xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"]
xfile.xahdr.Odsize = s.Ssize xfile.xahdr.Odsize = s.Ssize
xfile.sectData = s
s = xfile.addSection(".bss", Segdata.Vaddr+Segdata.Filelen, Segdata.Length-Segdata.Filelen, 0, STYP_BSS) s = xfile.addSection(".bss", segdataVaddr+segdataFilelen, segbssFilelen, 0, STYP_BSS)
xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"] xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"]
xfile.xahdr.Obsize = s.Ssize xfile.xahdr.Obsize = s.Ssize
xfile.sectBss = s
if ctxt.LinkMode == LinkExternal {
var tbss *sym.Section
for _, s := range Segdata.Sections {
if s.Name == ".tbss" {
tbss = s
break
}
}
s = xfile.addSection(".tbss", tbss.Vaddr, tbss.Length, 0, STYP_TBSS)
}
// add dwarf sections // add dwarf sections
for _, sect := range Segdwarf.Sections { for _, sect := range Segdwarf.Sections {
...@@ -1405,13 +1490,20 @@ func Asmbxcoff(ctxt *Link, fileoff int64) { ...@@ -1405,13 +1490,20 @@ func Asmbxcoff(ctxt *Link, fileoff int64) {
Loaderblk(ctxt, uint64(fileoff)) Loaderblk(ctxt, uint64(fileoff))
s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER) s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER)
xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"] xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"]
// Update fileoff for symbol table
fileoff += int64(xfile.loaderSize)
} }
} else {
// TODO: Relocation
} }
// Write symtab // Create Symbol table
xfile.asmaixsym(ctxt) xfile.asmaixsym(ctxt)
if ctxt.LinkMode == LinkExternal {
xfile.emitRelocations(ctxt, fileoff)
}
// Write Symbol table
xfile.symtabOffset = ctxt.Out.Offset() xfile.symtabOffset = ctxt.Out.Offset()
for _, s := range xfile.symtabSym { for _, s := range xfile.symtabSym {
binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
...@@ -1424,3 +1516,101 @@ func Asmbxcoff(ctxt *Link, fileoff int64) { ...@@ -1424,3 +1516,101 @@ func Asmbxcoff(ctxt *Link, fileoff int64) {
// write headers // write headers
xcoffwrite(ctxt) xcoffwrite(ctxt)
} }
// byOffset is used to sort relocations by offset
type byOffset []sym.Reloc
func (x byOffset) Len() int { return len(x) }
func (x byOffset) Swap(i, j int) {
x[i], x[j] = x[j], x[i]
}
func (x byOffset) Less(i, j int) bool {
return x[i].Off < x[j].Off
}
// emitRelocations emits relocation entries for go.o in external linking.
func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) {
ctxt.Out.SeekSet(fileoff)
for ctxt.Out.Offset()&7 != 0 {
ctxt.Out.Write8(0)
}
// relocsect relocates symbols from first in section sect, and returns
// the total number of relocations emitted.
relocsect := func(sect *sym.Section, syms []*sym.Symbol, base uint64) uint32 {
// ctxt.Logf("%s 0x%x\n", sect.Name, sect.Vaddr)
// If main section has no bits, nothing to relocate.
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
return 0
}
sect.Reloff = uint64(ctxt.Out.Offset())
for i, s := range syms {
if !s.Attr.Reachable() {
continue
}
if uint64(s.Value) >= sect.Vaddr {
syms = syms[i:]
break
}
}
eaddr := int64(sect.Vaddr + sect.Length)
for _, s := range syms {
if !s.Attr.Reachable() {
continue
}
if s.Value >= int64(eaddr) {
break
}
// Relocation must be ordered by address, so s.R is ordered by Off.
sort.Sort(byOffset(s.R))
for ri := range s.R {
r := &s.R[ri]
// ctxt.Logf("%s reloc %d(%s)/%d to %s\n", s, r.Type, r.Type.String(), r.Siz, r.Sym.Name)
if r.Done {
continue
}
if r.Xsym == nil {
Errorf(s, "missing xsym in relocation")
continue
}
if r.Xsym.Dynid < 0 {
Errorf(s, "reloc %s to non-coff symbol %s (outer=%s) %d %d", r.Type.String(), r.Sym.Name, r.Xsym.Name, r.Sym.Type, r.Xsym.Dynid)
}
if !thearch.Xcoffreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-base)) {
Errorf(s, "unsupported obj reloc %d(%s)/%d to %s", r.Type, r.Type.String(), r.Siz, r.Sym.Name)
}
}
}
sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
return uint32(sect.Rellen) / RELSZ_64
}
sects := []struct {
xcoffSect *XcoffScnHdr64
segs []*sym.Segment
}{
{f.sectText, []*sym.Segment{&Segtext}},
{f.sectData, []*sym.Segment{&Segrelrodata, &Segdata}},
}
for _, s := range sects {
s.xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
n := uint32(0)
for _, seg := range s.segs {
for _, sect := range seg.Sections {
if sect.Name == ".text" {
n += relocsect(sect, ctxt.Textp, 0)
} else {
n += relocsect(sect, datap, 0)
}
}
}
s.xcoffSect.Snreloc += n
}
// TODO(aix): DWARF relocations
}
...@@ -382,6 +382,43 @@ func addelfdynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { ...@@ -382,6 +382,43 @@ func addelfdynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
return false return false
} }
func xcoffreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
rs := r.Xsym
emitReloc := func(v uint16, off uint64) {
out.Write64(uint64(sectoff) + off)
out.Write32(uint32(rs.Dynid))
out.Write16(v)
}
var v uint16
switch r.Type {
default:
return false
case objabi.R_ADDR:
v = ld.XCOFF_R_POS
if r.Siz == 4 {
v |= 0x1F << 8
} else {
v |= 0x3F << 8
}
emitReloc(v, 0)
case objabi.R_ADDRPOWER_TOCREL:
case objabi.R_ADDRPOWER_TOCREL_DS:
emitReloc(ld.XCOFF_R_TOCU|(0x0F<<8), 2)
emitReloc(ld.XCOFF_R_TOCL|(0x0F<<8), 6)
case objabi.R_POWER_TLS_LE:
emitReloc(ld.XCOFF_R_TLS_LE|0x0F<<8, 2)
case objabi.R_CALLPOWER:
if r.Siz != 4 {
return false
}
emitReloc(ld.XCOFF_R_RBR|0x19<<8, 0)
}
return true
}
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
// Beware that bit0~bit15 start from the third byte of a instruction in Big-Endian machines. // Beware that bit0~bit15 start from the third byte of a instruction in Big-Endian machines.
if r.Type == objabi.R_ADDR || r.Type == objabi.R_POWER_TLS || r.Type == objabi.R_CALLPOWER { if r.Type == objabi.R_ADDR || r.Type == objabi.R_POWER_TLS || r.Type == objabi.R_CALLPOWER {
...@@ -514,7 +551,7 @@ func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 { ...@@ -514,7 +551,7 @@ func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
ld.Errorf(s, "archreloctoc called for a symbol without TOC anchor") ld.Errorf(s, "archreloctoc called for a symbol without TOC anchor")
} }
if tarSym != nil && tarSym.Attr.Reachable() && (tarSym.Sect.Seg == &ld.Segdata) { if ctxt.LinkMode == ld.LinkInternal && tarSym != nil && tarSym.Attr.Reachable() && (tarSym.Sect.Seg == &ld.Segdata) {
t = ld.Symaddr(tarSym) + r.Add - ctxt.Syms.ROLookup("TOC", 0).Value t = ld.Symaddr(tarSym) + r.Add - ctxt.Syms.ROLookup("TOC", 0).Value
// change ld to addi in the second instruction // change ld to addi in the second instruction
o2 = (o2 & 0x03FF0000) | 0xE<<26 o2 = (o2 & 0x03FF0000) | 0xE<<26
...@@ -704,9 +741,13 @@ func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, o ...@@ -704,9 +741,13 @@ func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, o
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
if ctxt.LinkMode == ld.LinkExternal { if ctxt.LinkMode == ld.LinkExternal {
// On AIX, relocations (except TLS ones) must be also done to the
// value with the current addresses.
switch r.Type { switch r.Type {
default: default:
if ctxt.HeadType != objabi.Haix {
return val, false return val, false
}
case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE: case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE:
r.Done = false r.Done = false
// check Outer is nil, Type is TLSBSS? // check Outer is nil, Type is TLSBSS?
...@@ -734,14 +775,18 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo ...@@ -734,14 +775,18 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
} }
r.Xsym = rs r.Xsym = rs
if ctxt.HeadType != objabi.Haix {
return val, true return val, true
}
case objabi.R_CALLPOWER: case objabi.R_CALLPOWER:
r.Done = false r.Done = false
r.Xsym = r.Sym r.Xsym = r.Sym
r.Xadd = r.Add r.Xadd = r.Add
if ctxt.HeadType != objabi.Haix {
return val, true return val, true
} }
} }
}
switch r.Type { switch r.Type {
case objabi.R_CONST: case objabi.R_CONST:
......
...@@ -59,6 +59,7 @@ func Init() (*sys.Arch, ld.Arch) { ...@@ -59,6 +59,7 @@ func Init() (*sys.Arch, ld.Arch) {
Gentext: gentext, Gentext: gentext,
Trampoline: trampoline, Trampoline: trampoline,
Machoreloc1: machoreloc1, Machoreloc1: machoreloc1,
Xcoffreloc1: xcoffreloc1,
// TODO(austin): ABI v1 uses /usr/lib/ld.so.1, // TODO(austin): ABI v1 uses /usr/lib/ld.so.1,
Linuxdynld: "/lib64/ld64.so.1", Linuxdynld: "/lib64/ld64.so.1",
......
...@@ -784,11 +784,18 @@ TEXT runtime·setg(SB), NOSPLIT, $0-8 ...@@ -784,11 +784,18 @@ TEXT runtime·setg(SB), NOSPLIT, $0-8
RET RET
#ifdef GOARCH_ppc64 #ifdef GOARCH_ppc64
#ifdef GOOS_aix
DATA setg_gcc<>+0(SB)/8, $_setg_gcc<>(SB)
DATA setg_gcc<>+8(SB)/8, $TOC(SB)
DATA setg_gcc<>+16(SB)/8, $0
GLOBL setg_gcc<>(SB), NOPTR, $24
#else
TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0
DWORD $_setg_gcc<>(SB) DWORD $_setg_gcc<>(SB)
DWORD $0 DWORD $0
DWORD $0 DWORD $0
#endif #endif
#endif
// void setg_gcc(G*); set g in C TLS. // void setg_gcc(G*); set g in C TLS.
// Must obey the gcc calling convention. // Must obey the gcc calling convention.
......
...@@ -34,6 +34,15 @@ TEXT __start<>(SB),NOSPLIT,$-8 ...@@ -34,6 +34,15 @@ TEXT __start<>(SB),NOSPLIT,$-8
MOVD 40(R1), R2 MOVD 40(R1), R2
MOVD R14, R3 // argc MOVD R14, R3 // argc
MOVD R15, R4 // argv MOVD R15, R4 // argv
BL _main(SB)
DATA main+0(SB)/8, $_main(SB)
DATA main+8(SB)/8, $TOC(SB)
DATA main+16(SB)/8, $0
GLOBL main(SB), NOPTR, $24
TEXT _main(SB),NOSPLIT,$-8
MOVD $runtime·rt0_go(SB), R12 MOVD $runtime·rt0_go(SB), R12
MOVD R12, CTR MOVD R12, CTR
BR (CTR) BR (CTR)
......
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