diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index e0591c3959..43a0e06e90 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1710,21 +1710,9 @@ func (state *dodataState) allocateDataSections(ctxt *Link) { } ldr := ctxt.loader - // .got (and .toc on ppc64) + // .got if len(state.data[sym.SELFGOT]) > 0 { - sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06) - if ctxt.IsPPC64() { - for _, s := range state.data[sym.SELFGOT] { - // Resolve .TOC. symbol for this object file (ppc64) - - toc := ldr.Lookup(".TOC.", int(ldr.SymVersion(s))) - if toc != 0 { - ldr.SetSymSect(toc, sect) - ldr.AddInteriorSym(s, toc) - ldr.SetSymValue(toc, 0x8000) - } - } - } + state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06) } /* pointer-free data */ @@ -2690,6 +2678,24 @@ func (ctxt *Link) address() []*sym.Segment { ldr.SetSymSect(ldr.Lookup("_end", 0), ldr.SymSect(end)) } + if ctxt.IsPPC64() && ctxt.IsElf() { + // Resolve .TOC. symbols for all objects. Only one TOC region is supported. If a + // GOT section is present, compute it as suggested by the ELFv2 ABI. Otherwise, + // choose a similar offset from the start of the data segment. + tocAddr := int64(Segdata.Vaddr) + 0x8000 + if gotAddr := ldr.SymValue(ctxt.GOT); gotAddr != 0 { + tocAddr = gotAddr + 0x8000 + } + for i, _ := range ctxt.DotTOC { + if i >= sym.SymVerABICount && i < sym.SymVerStatic { // these versions are not used currently + continue + } + if toc := ldr.Lookup(".TOC.", i); toc != 0 { + ldr.SetSymValue(toc, tocAddr) + } + } + } + return order } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 494fea5e72..cf70374b16 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -149,16 +149,9 @@ func (ctxt *Link) setArchSyms() { if ctxt.IsPPC64() { ctxt.mkArchSym("TOC", 0, &ctxt.TOC) - // NB: note the +2 below for DotTOC2 compared to the +1 for - // DocTOC. This is because loadlibfull() creates an additional - // syms version during conversion of loader.Sym symbols to - // *sym.Symbol symbols. Symbols that are assigned this final - // version are not going to have TOC references, so it should - // be ok for them to inherit an invalid .TOC. symbol. - // TODO: revisit the +2, now that loadlibfull is gone. - ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+2) + ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+1) for i := 0; i <= ctxt.MaxVersion(); i++ { - if i >= 2 && i < sym.SymVerStatic { // these versions are not used currently + if i >= sym.SymVerABICount && i < sym.SymVerStatic { // these versions are not used currently continue } ctxt.mkArchSymVec(".TOC.", i, ctxt.DotTOC) diff --git a/src/cmd/link/internal/sym/symbol.go b/src/cmd/link/internal/sym/symbol.go index 70cf36a87e..4687aa53bb 100644 --- a/src/cmd/link/internal/sym/symbol.go +++ b/src/cmd/link/internal/sym/symbol.go @@ -11,6 +11,7 @@ import ( const ( SymVerABI0 = 0 SymVerABIInternal = 1 + SymVerABICount = 2 // Number of internal ABIs SymVerStatic = 10 // Minimum version used by static (file-local) syms )