]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/link: rework .TOC. handling for ppc64le
authorPaul E. Murphy <murp@ibm.com>
Tue, 23 Mar 2021 20:52:49 +0000 (15:52 -0500)
committerLynn Boger <laboger@linux.vnet.ibm.com>
Wed, 8 Sep 2021 11:57:03 +0000 (11:57 +0000)
Setup .TOC. to point to the same place for all objects. Today, the linker
assumes all call relocations can use the local function entry point of
imported object files. This requires a consistent pointer across all
objects.

This intentionally computes the .TOC. pointer in all linking configurations.
In some cases the .TOC. is not used today (e.g linking position-dependent go
only code). It is harmless and simple to compute in all cases, so just
do it for easier maintenance.

Notably, .TOC. is used in some cases when static linking is requested on
ppc64le/linux:

* Position-independent C code using a PC-rel relocation against .TOC.. cgo
  generated C object files are usually compiled PIC even if the go binary
  itself is not.

* Anything which causes PLT stub generation. The stubs always generate
  a .TOC. relative relocation.

* The race detector. Today, this links in an externally compiled archive which
  contains position-independent object files.

Similarly, position-independent linking is always punted to the external
linker on ppc64 today.

Updates #21961
Fixes #15409

Change-Id: Ifd8294b9249e16ba8b92eaf876d15d162f9c61fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/304458
Reviewed-by: Cherry Mui <cherryyz@google.com>
Trust: Lynn Boger <laboger@linux.vnet.ibm.com>

src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/sym/symbol.go

index e0591c3959496a12dfa3e0b2e9462ae2da5a3c1f..43a0e06e9013c887e17de8537ad027d8c86f1bc5 100644 (file)
@@ -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
 }
 
index 494fea5e724c1dae4578e6664e2f79356278621f..cf70374b163a3598ef9e7850236747a08159c690 100644 (file)
@@ -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)
index 70cf36a87ee9bed9ef6cb080fed71d2e99c4ae8d..4687aa53bbf6ea3db460b7980a72a1602540af27 100644 (file)
@@ -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
 )