]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: convert text address assignment to new style
authorCherry Zhang <cherryyz@google.com>
Mon, 6 Apr 2020 19:58:21 +0000 (15:58 -0400)
committerCherry Zhang <cherryyz@google.com>
Wed, 8 Apr 2020 15:32:39 +0000 (15:32 +0000)
Implement text address assignment and trampoline generation using
the loader.

Note: the trampoline insertion part doesn't actually work. It
also needs to propagate Aux symbols for external symbols in
LoadFull.  But it won't be needed after converting pclntab
generation, so I'll leave it out for now. This could break
linking large binaries on PPC64 and ARM.

Change-Id: Ie46a35b25d7c027983dd877207cfa8f67c32530b
Reviewed-on: https://go-review.googlesource.com/c/go/+/227482
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/link/internal/arm/asm.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/link.go
src/cmd/link/internal/ld/main.go
src/cmd/link/internal/loader/loader.go
src/cmd/link/internal/loader/symbolbuilder.go
src/cmd/link/internal/ppc64/asm.go
src/cmd/link/internal/wasm/asm.go

index bb0ddf98780c35cf818ebf8ad9225b024a82639b..18fc54a7e27b129342e144cb8182d236a4ca2747 100644 (file)
@@ -443,109 +443,120 @@ func immrot(v uint32) uint32 {
 }
 
 // Convert the direct jump relocation r to refer to a trampoline if the target is too far
-func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
-       switch r.Type {
+func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
+       relocs := ldr.Relocs(s)
+       r := relocs.At2(ri)
+       switch r.Type() {
        case objabi.R_CALLARM:
                // r.Add is the instruction
                // low 24-bit encodes the target address
-               t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
-               if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
+               t := (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
+               if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
                        // direct call too far, need to insert trampoline.
                        // look up existing trampolines first. if we found one within the range
                        // of direct call, we can reuse it. otherwise create a new one.
-                       offset := (signext24(r.Add&0xffffff) + 2) * 4
-                       var tramp *sym.Symbol
+                       offset := (signext24(r.Add()&0xffffff) + 2) * 4
+                       var tramp loader.Sym
                        for i := 0; ; i++ {
-                               name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i)
-                               tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
-                               if tramp.Type == sym.SDYNIMPORT {
+                               name := ldr.SymName(rs) + fmt.Sprintf("%+d-tramp%d", offset, i)
+                               tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
+                               if ldr.SymType(tramp) == sym.SDYNIMPORT {
                                        // don't reuse trampoline defined in other module
                                        continue
                                }
-                               if tramp.Value == 0 {
+                               if ldr.SymValue(tramp) == 0 {
                                        // either the trampoline does not exist -- we need to create one,
                                        // or found one the address which is not assigned -- this will be
                                        // laid down immediately after the current function. use this one.
                                        break
                                }
 
-                               t = (ld.Symaddr(tramp) - 8 - (s.Value + int64(r.Off))) / 4
+                               t = (ldr.SymValue(tramp) - 8 - (ldr.SymValue(s) + int64(r.Off()))) / 4
                                if t >= -0x800000 && t < 0x7fffff {
                                        // found an existing trampoline that is not too far
                                        // we can just use it
                                        break
                                }
                        }
-                       if tramp.Type == 0 {
+                       if ldr.SymType(tramp) == 0 {
                                // trampoline does not exist, create one
-                               ctxt.AddTramp(tramp)
+                               trampb := ldr.MakeSymbolUpdater(tramp)
+                               ctxt.AddTramp(trampb)
                                if ctxt.DynlinkingGo() {
                                        if immrot(uint32(offset)) == 0 {
-                                               ld.Errorf(s, "odd offset in dynlink direct call: %v+%d", r.Sym, offset)
+                                               ctxt.Errorf(s, "odd offset in dynlink direct call: %v+%d", ldr.SymName(rs), offset)
                                        }
-                                       gentrampdyn(ctxt.Arch, tramp, r.Sym, int64(offset))
+                                       gentrampdyn(ctxt.Arch, trampb, rs, int64(offset))
                                } else if ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE {
-                                       gentramppic(ctxt.Arch, tramp, r.Sym, int64(offset))
+                                       gentramppic(ctxt.Arch, trampb, rs, int64(offset))
                                } else {
-                                       gentramp(ctxt.Arch, ctxt.LinkMode, tramp, r.Sym, int64(offset))
+                                       gentramp(ctxt.Arch, ctxt.LinkMode, ldr, trampb, rs, int64(offset))
                                }
                        }
                        // modify reloc to point to tramp, which will be resolved later
-                       r.Sym = tramp
-                       r.Add = r.Add&0xff000000 | 0xfffffe // clear the offset embedded in the instruction
-                       r.Done = false
+                       sb := ldr.MakeSymbolUpdater(s)
+                       relocs := sb.Relocs()
+                       r := relocs.At2(ri)
+                       r.SetSym(tramp)
+                       r.SetAdd(r.Add()&0xff000000 | 0xfffffe) // clear the offset embedded in the instruction
                }
        default:
-               ld.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
+               ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
        }
 }
 
 // generate a trampoline to target+offset
-func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, offset int64) {
-       tramp.Size = 12 // 3 instructions
-       tramp.P = make([]byte, tramp.Size)
-       t := ld.Symaddr(target) + offset
+func gentramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
+       tramp.SetSize(12) // 3 instructions
+       P := make([]byte, tramp.Size())
+       t := ldr.SymValue(target) + offset
        o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8
        o2 := uint32(0xe12fff10 | 11)              // JMP  (R11)
        o3 := uint32(t)                            // WORD $target
-       arch.ByteOrder.PutUint32(tramp.P, o1)
-       arch.ByteOrder.PutUint32(tramp.P[4:], o2)
-       arch.ByteOrder.PutUint32(tramp.P[8:], o3)
+       arch.ByteOrder.PutUint32(P, o1)
+       arch.ByteOrder.PutUint32(P[4:], o2)
+       arch.ByteOrder.PutUint32(P[8:], o3)
+       tramp.SetData(P)
 
        if linkmode == ld.LinkExternal {
-               r := tramp.AddRel()
-               r.Off = 8
-               r.Type = objabi.R_ADDR
-               r.Siz = 4
-               r.Sym = target
-               r.Add = offset
+               r := loader.Reloc{
+                       Off: 8,
+                       Type: objabi.R_ADDR,
+                       Size: 4,
+                       Sym: target,
+                       Add: offset,
+               }
+               tramp.AddReloc(r)
        }
 }
 
 // generate a trampoline to target+offset in position independent code
-func gentramppic(arch *sys.Arch, tramp, target *sym.Symbol, offset int64) {
-       tramp.Size = 16 // 4 instructions
-       tramp.P = make([]byte, tramp.Size)
+func gentramppic(arch *sys.Arch, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
+       tramp.SetSize(16) // 4 instructions
+       P := make([]byte, tramp.Size())
        o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 4)  // MOVW 4(R15), R11 // R15 is actual pc + 8
        o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
        o3 := uint32(0xe12fff10 | 11)                   // JMP  (R11)
        o4 := uint32(0)                                 // WORD $(target-pc) // filled in with relocation
-       arch.ByteOrder.PutUint32(tramp.P, o1)
-       arch.ByteOrder.PutUint32(tramp.P[4:], o2)
-       arch.ByteOrder.PutUint32(tramp.P[8:], o3)
-       arch.ByteOrder.PutUint32(tramp.P[12:], o4)
-
-       r := tramp.AddRel()
-       r.Off = 12
-       r.Type = objabi.R_PCREL
-       r.Siz = 4
-       r.Sym = target
-       r.Add = offset + 4
+       arch.ByteOrder.PutUint32(P, o1)
+       arch.ByteOrder.PutUint32(P[4:], o2)
+       arch.ByteOrder.PutUint32(P[8:], o3)
+       arch.ByteOrder.PutUint32(P[12:], o4)
+       tramp.SetData(P)
+
+       r := loader.Reloc{
+               Off: 12,
+               Type: objabi.R_PCREL,
+               Size: 4,
+               Sym: target,
+               Add: offset + 4,
+       }
+       tramp.AddReloc(r)
 }
 
 // generate a trampoline to target+offset in dynlink mode (using GOT)
-func gentrampdyn(arch *sys.Arch, tramp, target *sym.Symbol, offset int64) {
-       tramp.Size = 20                                 // 5 instructions
+func gentrampdyn(arch *sys.Arch, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
+       tramp.SetSize(20)                               // 5 instructions
        o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 8)  // MOVW 8(R15), R11 // R15 is actual pc + 8
        o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
        o3 := uint32(0xe5900000 | 11<<12 | 11<<16)      // MOVW (R11), R11
@@ -554,33 +565,36 @@ func gentrampdyn(arch *sys.Arch, tramp, target *sym.Symbol, offset int64) {
        o6 := uint32(0)
        if offset != 0 {
                // insert an instruction to add offset
-               tramp.Size = 24 // 6 instructions
+               tramp.SetSize(24) // 6 instructions
                o6 = o5
                o5 = o4
                o4 = 0xe2800000 | 11<<12 | 11<<16 | immrot(uint32(offset)) // ADD $offset, R11, R11
                o1 = uint32(0xe5900000 | 11<<12 | 15<<16 | 12)             // MOVW 12(R15), R11
        }
-       tramp.P = make([]byte, tramp.Size)
-       arch.ByteOrder.PutUint32(tramp.P, o1)
-       arch.ByteOrder.PutUint32(tramp.P[4:], o2)
-       arch.ByteOrder.PutUint32(tramp.P[8:], o3)
-       arch.ByteOrder.PutUint32(tramp.P[12:], o4)
-       arch.ByteOrder.PutUint32(tramp.P[16:], o5)
+       P := make([]byte, tramp.Size())
+       arch.ByteOrder.PutUint32(P, o1)
+       arch.ByteOrder.PutUint32(P[4:], o2)
+       arch.ByteOrder.PutUint32(P[8:], o3)
+       arch.ByteOrder.PutUint32(P[12:], o4)
+       arch.ByteOrder.PutUint32(P[16:], o5)
        if offset != 0 {
-               arch.ByteOrder.PutUint32(tramp.P[20:], o6)
+               arch.ByteOrder.PutUint32(P[20:], o6)
        }
+       tramp.SetData(P)
 
-       r := tramp.AddRel()
-       r.Off = 16
-       r.Type = objabi.R_GOTPCREL
-       r.Siz = 4
-       r.Sym = target
-       r.Add = 8
+       r := loader.Reloc{
+               Off: 16,
+               Type: objabi.R_GOTPCREL,
+               Size: 4,
+               Sym: target,
+               Add: 8,
+       }
        if offset != 0 {
                // increase reloc offset by 4 as we inserted an ADD instruction
                r.Off = 20
                r.Add = 12
        }
+       tramp.AddReloc(r)
 }
 
 func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
index 7c4b08a8051cbd09bb0a0f9059dc5bbf5c7c09a4..3a1f355056e0b7cb627f14520fbd22af3bfd4a1b 100644 (file)
@@ -65,7 +65,7 @@ func isRuntimeDepPkg(pkg string) bool {
 // Estimate the max size needed to hold any new trampolines created for this function. This
 // is used to determine when the section can be split if it becomes too large, to ensure that
 // the trampolines are in the same section as the function that uses them.
-func maxSizeTrampolinesPPC64(s *sym.Symbol, isTramp bool) uint64 {
+func maxSizeTrampolinesPPC64(ldr *loader.Loader, s loader.Sym, isTramp bool) uint64 {
        // If thearch.Trampoline is nil, then trampoline support is not available on this arch.
        // A trampoline does not need any dependent trampolines.
        if thearch.Trampoline == nil || isTramp {
@@ -73,9 +73,10 @@ func maxSizeTrampolinesPPC64(s *sym.Symbol, isTramp bool) uint64 {
        }
 
        n := uint64(0)
-       for ri := range s.R {
-               r := &s.R[ri]
-               if r.Type.IsDirectCallOrJump() {
+       relocs := ldr.Relocs(s)
+       for ri := 0; ri < relocs.Count(); ri++ {
+               r := relocs.At2(ri)
+               if r.Type().IsDirectCallOrJump() {
                        n++
                }
        }
@@ -87,20 +88,27 @@ func maxSizeTrampolinesPPC64(s *sym.Symbol, isTramp bool) uint64 {
 // ARM, PPC64 & PPC64LE support trampoline insertion for internal and external linking
 // On PPC64 & PPC64LE the text sections might be split but will still insert trampolines
 // where necessary.
-func trampoline(ctxt *Link, s *sym.Symbol) {
+func trampoline(ctxt *Link, s loader.Sym) {
        if thearch.Trampoline == nil {
                return // no need or no support of trampolines on this arch
        }
 
-       for ri := range s.R {
-               r := &s.R[ri]
-               if !r.Type.IsDirectCallOrJump() {
+       ldr := ctxt.loader
+       relocs := ldr.Relocs(s)
+       for ri := 0; ri < relocs.Count(); ri++ {
+               r := relocs.At2(ri)
+               if !r.Type().IsDirectCallOrJump() {
                        continue
                }
-               if Symaddr(r.Sym) == 0 && (r.Sym.Type != sym.SDYNIMPORT && r.Sym.Type != sym.SUNDEFEXT) {
-                       if r.Sym.File != s.File {
-                               if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) {
-                                       ctxt.errorUnresolved(s, r)
+               rs := r.Sym()
+               if !ldr.AttrReachable(rs) {
+                       continue // something is wrong. skip it here and we'll emit a better error later
+               }
+               rs = ldr.ResolveABIAlias(rs)
+               if ldr.SymValue(rs) == 0 && (ldr.SymType(rs) != sym.SDYNIMPORT && ldr.SymType(rs) != sym.SUNDEFEXT) {
+                       if ldr.SymPkg(rs) != ldr.SymPkg(s) {
+                               if !isRuntimeDepPkg(ldr.SymPkg(s)) || !isRuntimeDepPkg(ldr.SymPkg(rs)) {
+                                       ctxt.Errorf(s, "unresolved inter-package jump to %s(%s) from %s", ldr.SymName(rs), ldr.SymPkg(rs), ldr.SymPkg(s))
                                }
                                // runtime and its dependent packages may call to each other.
                                // they are fine, as they will be laid down together.
@@ -108,7 +116,7 @@ func trampoline(ctxt *Link, s *sym.Symbol) {
                        continue
                }
 
-               thearch.Trampoline(ctxt, r, s)
+               thearch.Trampoline(ctxt, ldr, ri, rs, s)
        }
 
 }
@@ -2175,30 +2183,33 @@ func (ctxt *Link) textaddress() {
 
        sect.Align = int32(Funcalign)
 
-       text := ctxt.Syms.Lookup("runtime.text", 0)
-       text.Sect = sect
-       if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
+       ldr := ctxt.loader
+       text := ldr.LookupOrCreateSym("runtime.text", 0)
+       ldr.SetAttrReachable(text, true)
+       ldr.SetSymSect(text, sect)
+       if ctxt.IsAIX() && ctxt.IsExternal() {
                // Setting runtime.text has a real symbol prevents ld to
                // change its base address resulting in wrong offsets for
                // reflect methods.
-               text.Align = sect.Align
-               text.Size = 0x8
+               u := ldr.MakeSymbolUpdater(text)
+               u.SetAlign(sect.Align)
+               u.SetSize(8)
        }
 
-       if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
-               etext := ctxt.Syms.Lookup("runtime.etext", 0)
-               etext.Sect = sect
+       if (ctxt.DynlinkingGo() && ctxt.IsDarwin()) || (ctxt.IsAIX() && ctxt.IsExternal()) {
+               etext := ldr.LookupOrCreateSym("runtime.etext", 0)
+               ldr.SetSymSect(etext, sect)
 
-               ctxt.Textp = append(ctxt.Textp, etext, nil)
-               copy(ctxt.Textp[1:], ctxt.Textp)
-               ctxt.Textp[0] = text
+               ctxt.Textp2 = append(ctxt.Textp2, etext, 0)
+               copy(ctxt.Textp2[1:], ctxt.Textp2)
+               ctxt.Textp2[0] = text
        }
 
        va := uint64(*FlagTextAddr)
        n := 1
        sect.Vaddr = va
        ntramps := 0
-       for _, s := range ctxt.Textp {
+       for _, s := range ctxt.Textp2 {
                sect, n, va = assignAddress(ctxt, sect, n, s, va, false)
 
                trampoline(ctxt, s) // resolve jumps, may add trampolines if jump too far
@@ -2206,7 +2217,7 @@ func (ctxt *Link) textaddress() {
                // lay down trampolines after each function
                for ; ntramps < len(ctxt.tramps); ntramps++ {
                        tramp := ctxt.tramps[ntramps]
-                       if ctxt.HeadType == objabi.Haix && strings.HasPrefix(tramp.Name, "runtime.text.") {
+                       if ctxt.IsAIX() && strings.HasPrefix(ldr.SymName(tramp), "runtime.text.") {
                                // Already set in assignAddress
                                continue
                        }
@@ -2215,49 +2226,50 @@ func (ctxt *Link) textaddress() {
        }
 
        sect.Length = va - sect.Vaddr
-       ctxt.Syms.Lookup("runtime.etext", 0).Sect = sect
+       etext := ldr.LookupOrCreateSym("runtime.etext", 0)
+       ldr.SetAttrReachable(etext, true)
+       ldr.SetSymSect(etext, sect)
 
        // merge tramps into Textp, keeping Textp in address order
        if ntramps != 0 {
-               newtextp := make([]*sym.Symbol, 0, len(ctxt.Textp)+ntramps)
+               newtextp := make([]loader.Sym, 0, len(ctxt.Textp)+ntramps)
                i := 0
-               for _, s := range ctxt.Textp {
-                       for ; i < ntramps && ctxt.tramps[i].Value < s.Value; i++ {
+               for _, s := range ctxt.Textp2 {
+                       for ; i < ntramps && ldr.SymValue(ctxt.tramps[i]) < ldr.SymValue(s); i++ {
                                newtextp = append(newtextp, ctxt.tramps[i])
                        }
                        newtextp = append(newtextp, s)
                }
                newtextp = append(newtextp, ctxt.tramps[i:ntramps]...)
 
-               ctxt.Textp = newtextp
+               ctxt.Textp2 = newtextp
        }
 }
 
 // assigns address for a text symbol, returns (possibly new) section, its number, and the address
-// Note: once we have trampoline insertion support for external linking, this function
-// will not need to create new text sections, and so no need to return sect and n.
-func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint64, isTramp bool) (*sym.Section, int, uint64) {
+func assignAddress(ctxt *Link, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64) {
+       ldr := ctxt.loader
        if thearch.AssignAddress != nil {
-               return thearch.AssignAddress(ctxt, sect, n, s, va, isTramp)
+               return thearch.AssignAddress(ldr, sect, n, s, va, isTramp)
        }
 
-       s.Sect = sect
-       if s.Attr.SubSymbol() {
+       ldr.SetSymSect(s, sect)
+       if ldr.AttrSubSymbol(s) {
                return sect, n, va
        }
-       if s.Align != 0 {
-               va = uint64(Rnd(int64(va), int64(s.Align)))
-       } else {
-               va = uint64(Rnd(int64(va), int64(Funcalign)))
-       }
 
-       funcsize := uint64(MINFUNC) // spacing required for findfunctab
-       if s.Size > MINFUNC {
-               funcsize = uint64(s.Size)
+       align := ldr.SymAlign(s)
+       if align == 0 {
+               align = int32(Funcalign)
+       }
+       va = uint64(Rnd(int64(va), int64(align)))
+       if sect.Align < align {
+               sect.Align = align
        }
 
-       if sect.Align < s.Align {
-               sect.Align = s.Align
+       funcsize := uint64(MINFUNC) // spacing required for findfunctab
+       if ldr.SymSize(s) > MINFUNC {
+               funcsize = uint64(ldr.SymSize(s))
        }
 
        // On ppc64x a text section should not be larger than 2^26 bytes due to the size of
@@ -2269,33 +2281,33 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
 
        // Only break at outermost syms.
 
-       if ctxt.Arch.InFamily(sys.PPC64) && s.Outer == nil && ctxt.LinkMode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(s, isTramp) > 0x1c00000 {
+       if ctxt.Arch.InFamily(sys.PPC64) && ldr.OuterSym(s) == 0 && ctxt.IsExternal() && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(ldr, s, isTramp) > 0x1c00000 {
                // Set the length for the previous text section
                sect.Length = va - sect.Vaddr
 
                // Create new section, set the starting Vaddr
                sect = addsection(ctxt.Arch, &Segtext, ".text", 05)
                sect.Vaddr = va
-               s.Sect = sect
+               ldr.SetSymSect(s, sect)
 
                // Create a symbol for the start of the secondary text sections
-               ntext := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
-               ntext.Sect = sect
-               if ctxt.HeadType == objabi.Haix {
+               ntext := ldr.CreateSymForUpdate(fmt.Sprintf("runtime.text.%d", n), 0)
+               ntext.SetReachable(true)
+               ntext.SetSect(sect)
+               if ctxt.IsAIX() {
                        // runtime.text.X must be a real symbol on AIX.
                        // Assign its address directly in order to be the
                        // first symbol of this new section.
-                       ntext.Type = sym.STEXT
-                       ntext.Size = int64(MINFUNC)
-                       ntext.Attr |= sym.AttrReachable
-                       ntext.Attr |= sym.AttrOnList
-                       ctxt.tramps = append(ctxt.tramps, ntext)
+                       ntext.SetType(sym.STEXT)
+                       ntext.SetSize(int64(MINFUNC))
+                       ntext.SetOnList(true)
+                       ctxt.tramps = append(ctxt.tramps, ntext.Sym())
 
-                       ntext.Value = int64(va)
-                       va += uint64(ntext.Size)
+                       ntext.SetValue(int64(va))
+                       va += uint64(ntext.Size())
 
-                       if s.Align != 0 {
-                               va = uint64(Rnd(int64(va), int64(s.Align)))
+                       if align := ldr.SymAlign(s); align != 0 {
+                               va = uint64(Rnd(int64(va), int64(align)))
                        } else {
                                va = uint64(Rnd(int64(va), int64(Funcalign)))
                        }
@@ -2303,9 +2315,9 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
                n++
        }
 
-       s.Value = 0
-       for sub := s; sub != nil; sub = sub.Sub {
-               sub.Value += int64(va)
+       ldr.SetSymValue(s, 0)
+       for sub := s; sub != 0; sub = ldr.SubSym(sub) {
+               ldr.SetSymValue(sub, ldr.SymValue(sub)+int64(va))
        }
 
        va += funcsize
@@ -2585,13 +2597,13 @@ func (ctxt *Link) layout(order []*sym.Segment) uint64 {
 }
 
 // add a trampoline with symbol s (to be laid down after the current function)
-func (ctxt *Link) AddTramp(s *sym.Symbol) {
-       s.Type = sym.STEXT
-       s.Attr |= sym.AttrReachable
-       s.Attr |= sym.AttrOnList
-       ctxt.tramps = append(ctxt.tramps, s)
+func (ctxt *Link) AddTramp(s *loader.SymbolBuilder) {
+       s.SetType(sym.STEXT)
+       s.SetReachable(true)
+       s.SetOnList(true)
+       ctxt.tramps = append(ctxt.tramps, s.Sym())
        if *FlagDebugTramp > 0 && ctxt.Debugvlog > 0 {
-               ctxt.Logf("trampoline %s inserted\n", s)
+               ctxt.Logf("trampoline %s inserted\n", s.Name())
        }
 }
 
index f16de043effa485cad05adadc6bdf633fc9250c4..e560fea2f1fa69548133f536e41984776726c7c9 100644 (file)
@@ -254,7 +254,10 @@ type Arch struct {
        // offset value.
        Archrelocvariant func(target *Target, syms *ArchSyms, rel *sym.Reloc, sym *sym.Symbol,
                offset int64) (relocatedOffset int64)
-       Trampoline func(*Link, *sym.Reloc, *sym.Symbol)
+
+       // Generate a trampoline for a call from s to rs if necessary. ri is
+       // index of the relocation.
+       Trampoline func(ctxt *Link, ldr *loader.Loader, ri int, rs, s loader.Sym)
 
        // Asmb and Asmb2 are arch-specific routines that write the output
        // file. Typically, Asmb writes most of the content (sections and
@@ -280,7 +283,7 @@ type Arch struct {
        TLSIEtoLE func(s *sym.Symbol, off, size int)
 
        // optional override for assignAddress
-       AssignAddress func(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint64, isTramp bool) (*sym.Section, int, uint64)
+       AssignAddress func(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64)
 }
 
 var (
index 24866d8e8cd2c1c8882fb9d222e506d72cb08b75..a2ea34ea222c2bee388d452d303bea96259e77af 100644 (file)
@@ -80,7 +80,7 @@ type Link struct {
        PackageFile  map[string]string
        PackageShlib map[string]string
 
-       tramps []*sym.Symbol // trampolines
+       tramps []loader.Sym // trampolines
 
        // Used to implement field tracking.
        Reachparent map[*sym.Symbol]*sym.Symbol
index 3b2fd0b659e963ed1e454180d60d7390f00453ae..b91a195694a659e97ed9cfd774a47e3547ec3590 100644 (file)
@@ -288,11 +288,10 @@ func Main(arch *sys.Arch, theArch Arch) {
        bench.Start("Gentext")
        thearch.Gentext2(ctxt, ctxt.loader) // trampolines, call stubs, etc.
 
-       bench.Start("loadlibfull")
-       ctxt.loadlibfull() // XXX do it here for now
-
        bench.Start("textaddress")
        ctxt.textaddress()
+       bench.Start("loadlibfull")
+       ctxt.loadlibfull() // XXX do it here for now
        bench.Start("pclntab")
        ctxt.pclntab()
        bench.Start("findfunctab")
index 32386ccbc0387dcf44910d1380bac09cd0f5f04a..3437b42b6521f0d0bb9fc13a9b92a3c2cf0ae5d8 100644 (file)
@@ -198,6 +198,7 @@ type Loader struct {
        payloadBatch []extSymPayload
        payloads     []*extSymPayload // contents of linker-materialized external syms
        values       []int64          // symbol values, indexed by global sym index
+       sects        []*sym.Section   // symbol's section, indexed by global index
 
        itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
 
@@ -286,6 +287,7 @@ type extSymPayload struct {
        relocs   []goobj2.Reloc2
        reltypes []objabi.RelocType // relocation types
        data     []byte
+       auxs     []goobj2.Aux2
 }
 
 const (
@@ -664,6 +666,16 @@ func (l *Loader) SymAttr(i Sym) uint8 {
        return r.Sym2(li).Flag()
 }
 
+// Returns the size of the i-th symbol.
+func (l *Loader) SymSize(i Sym) int64 {
+       if l.IsExternal(i) {
+               pp := l.getPayload(i)
+               return pp.size
+       }
+       r, li := l.toLocal(i)
+       return int64(r.Sym2(li).Siz())
+}
+
 // AttrReachable returns true for symbols that are transitively
 // referenced from the entry points. Unreachable symbols are not
 // written to the output.
@@ -983,6 +995,7 @@ func (l *Loader) growValues(reqLen int) {
        curLen := len(l.values)
        if reqLen > curLen {
                l.values = append(l.values, make([]int64, reqLen+1-curLen)...)
+               l.sects = append(l.sects, make([]*sym.Section, reqLen+1-curLen)...)
        }
 }
 
@@ -1043,6 +1056,16 @@ func (l *Loader) SetSymAlign(i Sym, align int32) {
        }
 }
 
+// SymValue returns the section of the i-th symbol. i is global index.
+func (l *Loader) SymSect(i Sym) *sym.Section {
+       return l.sects[i]
+}
+
+// SetSymValue sets the section of the i-th symbol. i is global index.
+func (l *Loader) SetSymSect(i Sym, sect *sym.Section) {
+       l.sects[i] = sect
+}
+
 // SymDynImplib returns the "dynimplib" attribute for the specified
 // symbol, making up a portion of the info for a symbol specified
 // on a "cgo_import_dynamic" compiler directive.
@@ -1518,11 +1541,20 @@ func (fi *FuncInfo) Pcsp() []byte {
 // TODO: more accessors.
 
 func (l *Loader) FuncInfo(i Sym) FuncInfo {
+       var r *oReader
+       var auxs []goobj2.Aux2
        if l.IsExternal(i) {
-               return FuncInfo{}
+               pp := l.getPayload(i)
+               if pp.objidx == 0 {
+                       return FuncInfo{}
+               }
+               r = l.objs[pp.objidx].r
+               auxs = pp.auxs
+       } else {
+               var li int
+               r, li = l.toLocal(i)
+               auxs = r.Auxs2(li)
        }
-       r, li := l.toLocal(i)
-       auxs := r.Auxs2(li)
        for j := range auxs {
                a := &auxs[j]
                if a.Type() == goobj2.AuxFuncInfo {
@@ -2160,13 +2192,16 @@ func (l *Loader) cloneToExternal(symIdx Sym) {
        // If we're overriding a data symbol, collect the associated
        // Gotype, so as to propagate it to the new symbol.
        auxs := r.Auxs2(li)
+       pp.auxs = auxs
+loop:
        for j := range auxs {
                a := &auxs[j]
                switch a.Type() {
                case goobj2.AuxGotype:
                        pp.gotype = l.resolve(r, a.Sym())
+                       break loop
                default:
-                       log.Fatalf("internal error: cloneToExternal applied to %s symbol %s with non-gotype aux data %d", skind.String(), sname, a.Type())
+                       // nothing to do
                }
        }
 
@@ -2226,6 +2261,7 @@ func (l *Loader) CopyAttributes(src Sym, dst Sym) {
 func (l *Loader) migrateAttributes(src Sym, dst *sym.Symbol) {
        dst.Value = l.SymValue(src)
        dst.Align = l.SymAlign(src)
+       dst.Sect = l.SymSect(src)
 
        dst.Attr.Set(sym.AttrReachable, l.AttrReachable(src))
        dst.Attr.Set(sym.AttrOnList, l.AttrOnList(src))
@@ -2680,6 +2716,7 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
                        }
                        if dupok {
                                lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(gi))
+                               continue
                        }
 
                        lib.Textp2 = append(lib.Textp2, sym.LoaderSym(gi))
index cb7dd1cb3c01dab332a58914ee25ebf26fc2d6e4..3d5dc876167b0dfc8dabb519058535b5caa4f831 100644 (file)
@@ -88,6 +88,7 @@ func (sb *SymbolBuilder) Dynimpvers() string     { return sb.l.SymDynimpvers(sb.
 func (sb *SymbolBuilder) SubSym() Sym            { return sb.l.SubSym(sb.symIdx) }
 func (sb *SymbolBuilder) GoType() Sym            { return sb.l.SymGoType(sb.symIdx) }
 func (sb *SymbolBuilder) VisibilityHidden() bool { return sb.l.AttrVisibilityHidden(sb.symIdx) }
+func (sb *SymbolBuilder) Sect() *sym.Section     { return sb.l.SymSect(sb.symIdx) }
 
 // Setters for symbol properties.
 
@@ -108,10 +109,10 @@ func (sb *SymbolBuilder) SetSpecial(value bool)      { sb.l.SetAttrSpecial(sb.sy
 func (sb *SymbolBuilder) SetVisibilityHidden(value bool) {
        sb.l.SetAttrVisibilityHidden(sb.symIdx, value)
 }
-
 func (sb *SymbolBuilder) SetNotInSymbolTable(value bool) {
        sb.l.SetAttrNotInSymbolTable(sb.symIdx, value)
 }
+func (sb *SymbolBuilder) SetSect(sect *sym.Section) { sb.l.SetSymSect(sb.symIdx, sect) }
 
 func (sb *SymbolBuilder) AddBytes(data []byte) {
        sb.setReachable()
index cb9328d6b22be34f4bd279109604186c65000216..bc090c8e7ca95355fdbff2e98e20471870f61d85 100644 (file)
@@ -645,78 +645,83 @@ func archrelocaddr(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Sy
 }
 
 // resolve direct jump relocation r in s, and add trampoline if necessary
-func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
+func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
 
        // Trampolines are created if the branch offset is too large and the linker cannot insert a call stub to handle it.
        // For internal linking, trampolines are always created for long calls.
        // For external linking, the linker can insert a call stub to handle a long call, but depends on having the TOC address in
        // r2.  For those build modes with external linking where the TOC address is not maintained in r2, trampolines must be created.
-       if ctxt.LinkMode == ld.LinkExternal && (ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE) {
+       if ctxt.IsExternal() && (ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE) {
                // No trampolines needed since r2 contains the TOC
                return
        }
 
-       t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
-       switch r.Type {
+       relocs := ldr.Relocs(s)
+       r := relocs.At2(ri)
+       t := ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
+       switch r.Type() {
        case objabi.R_CALLPOWER:
 
                // If branch offset is too far then create a trampoline.
 
-               if (ctxt.LinkMode == ld.LinkExternal && s.Sect != r.Sym.Sect) || (ctxt.LinkMode == ld.LinkInternal && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
-                       var tramp *sym.Symbol
+               if (ctxt.IsExternal() && ldr.SymSect(s) != ldr.SymSect(rs)) || (ctxt.IsInternal() && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
+                       var tramp loader.Sym
                        for i := 0; ; i++ {
 
                                // Using r.Add as part of the name is significant in functions like duffzero where the call
                                // target is at some offset within the function.  Calls to duff+8 and duff+256 must appear as
                                // distinct trampolines.
 
-                               name := r.Sym.Name
-                               if r.Add == 0 {
+                               name := ldr.SymName(rs)
+                               if r.Add() == 0 {
                                        name = name + fmt.Sprintf("-tramp%d", i)
                                } else {
-                                       name = name + fmt.Sprintf("%+x-tramp%d", r.Add, i)
+                                       name = name + fmt.Sprintf("%+x-tramp%d", r.Add(), i)
                                }
 
                                // Look up the trampoline in case it already exists
 
-                               tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
-                               if tramp.Value == 0 {
+                               tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
+                               if ldr.SymValue(tramp) == 0 {
                                        break
                                }
 
-                               t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off))
+                               t = ldr.SymValue(tramp) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
 
                                // With internal linking, the trampoline can be used if it is not too far.
                                // With external linking, the trampoline must be in this section for it to be reused.
-                               if (ctxt.LinkMode == ld.LinkInternal && int64(int32(t<<6)>>6) == t) || (ctxt.LinkMode == ld.LinkExternal && s.Sect == tramp.Sect) {
+                               if (ctxt.IsInternal() && int64(int32(t<<6)>>6) == t) || (ctxt.IsExternal() && ldr.SymSect(s) == ldr.SymSect(tramp)) {
                                        break
                                }
                        }
-                       if tramp.Type == 0 {
+                       if ldr.SymType(tramp) == 0 {
                                if ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE {
                                        // Should have returned for above cases
-                                       ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
+                                       ctxt.Errorf(s, "unexpected trampoline for shared or dynamic linking")
                                } else {
-                                       ctxt.AddTramp(tramp)
-                                       gentramp(ctxt, tramp, r.Sym, r.Add)
+                                       trampb := ldr.MakeSymbolUpdater(tramp)
+                                       ctxt.AddTramp(trampb)
+                                       gentramp(ctxt, ldr, trampb, rs, r.Add())
                                }
                        }
-                       r.Sym = tramp
-                       r.Add = 0 // This was folded into the trampoline target address
-                       r.Done = false
+                       sb := ldr.MakeSymbolUpdater(s)
+                       relocs := sb.Relocs()
+                       r := relocs.At2(ri)
+                       r.SetSym(tramp)
+                       r.SetAdd(0) // This was folded into the trampoline target address
                }
        default:
-               ld.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
+               ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
        }
 }
 
-func gentramp(ctxt *ld.Link, tramp, target *sym.Symbol, offset int64) {
-       tramp.Size = 16 // 4 instructions
-       tramp.P = make([]byte, tramp.Size)
-       t := ld.Symaddr(target) + offset
+func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
+       tramp.SetSize(16) // 4 instructions
+       P := make([]byte, tramp.Size())
+       t := ldr.SymValue(target) + offset
        var o1, o2 uint32
 
-       if ctxt.HeadType == objabi.Haix {
+       if ctxt.IsAIX() {
                // On AIX, the address is retrieved with a TOC symbol.
                // For internal linking, the "Linux" way might still be used.
                // However, all text symbols are accessed with a TOC symbol as
@@ -725,17 +730,19 @@ func gentramp(ctxt *ld.Link, tramp, target *sym.Symbol, offset int64) {
                o1 = uint32(0x3fe20000) // lis r2, toctargetaddr hi
                o2 = uint32(0xebff0000) // ld r31, toctargetaddr lo
 
-               toctramp := ctxt.Syms.Lookup("TOC."+tramp.Name, 0)
-               toctramp.Type = sym.SXCOFFTOC
-               toctramp.Attr |= sym.AttrReachable
+               toctramp := ldr.CreateSymForUpdate("TOC."+ldr.SymName(tramp.Sym()), 0)
+               toctramp.SetType(sym.SXCOFFTOC)
+               toctramp.SetReachable(true)
                toctramp.AddAddr(ctxt.Arch, target)
 
-               tr := tramp.AddRel()
-               tr.Off = 0
-               tr.Type = objabi.R_ADDRPOWER_TOCREL_DS
-               tr.Siz = 8 // generates 2 relocations:  HA + LO
-               tr.Sym = toctramp
-               tr.Add = offset
+               r := loader.Reloc{
+                       Off: 0,
+                       Type: objabi.R_ADDRPOWER_TOCREL_DS,
+                       Size: 8, // generates 2 relocations:  HA + LO
+                       Sym: toctramp.Sym(),
+                       Add: offset,
+               }
+               tramp.AddReloc(r)
        } else {
                // Used for default build mode for an executable
                // Address of the call target is generated using
@@ -745,14 +752,15 @@ func gentramp(ctxt *ld.Link, tramp, target *sym.Symbol, offset int64) {
 
                // With external linking, the target address must be
                // relocated using LO and HA
-               if ctxt.LinkMode == ld.LinkExternal {
-                       tr := tramp.AddRel()
-                       tr.Off = 0
-                       tr.Type = objabi.R_ADDRPOWER
-                       tr.Siz = 8 // generates 2 relocations:  HA + LO
-                       tr.Sym = target
-                       tr.Add = offset
-
+               if ctxt.IsExternal() {
+                       r := loader.Reloc{
+                               Off: 0,
+                               Type: objabi.R_ADDRPOWER,
+                               Size: 8, // generates 2 relocations:  HA + LO
+                               Sym: target,
+                               Add: offset,
+                       }
+                       tramp.AddReloc(r)
                } else {
                        // adjustment needed if lo has sign bit set
                        // when using addi to compute address
@@ -767,10 +775,11 @@ func gentramp(ctxt *ld.Link, tramp, target *sym.Symbol, offset int64) {
 
        o3 := uint32(0x7fe903a6) // mtctr r31
        o4 := uint32(0x4e800420) // bctr
-       ctxt.Arch.ByteOrder.PutUint32(tramp.P, o1)
-       ctxt.Arch.ByteOrder.PutUint32(tramp.P[4:], o2)
-       ctxt.Arch.ByteOrder.PutUint32(tramp.P[8:], o3)
-       ctxt.Arch.ByteOrder.PutUint32(tramp.P[12:], o4)
+       ctxt.Arch.ByteOrder.PutUint32(P, o1)
+       ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
+       ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
+       ctxt.Arch.ByteOrder.PutUint32(P[12:], o4)
+       tramp.SetData(P)
 }
 
 func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
index 6af52b46ff0ddf8389fc06e512a09ee7d752a2ad..4367decba5db95c9c38d93d5c510d24109b61061 100644 (file)
@@ -71,7 +71,7 @@ var wasmFuncTypes = map[string]*wasmFuncType{
        "memchr":                 {Params: []byte{I32, I32, I32}, Results: []byte{I32}},      // s, c, len -> index
 }
 
-func assignAddress(ctxt *ld.Link, sect *sym.Section, n int, s *sym.Symbol, va uint64, isTramp bool) (*sym.Section, int, uint64) {
+func assignAddress(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64) {
        // WebAssembly functions do not live in the same address space as the linear memory.
        // Instead, WebAssembly automatically assigns indices. Imported functions (section "import")
        // have indices 0 to n. They are followed by native functions (sections "function" and "code")
@@ -86,8 +86,8 @@ func assignAddress(ctxt *ld.Link, sect *sym.Section, n int, s *sym.Symbol, va ui
        // The field "s.Value" corresponds to the concept of PC at runtime.
        // However, there is no PC register, only PC_F and PC_B. PC_F denotes the function,
        // PC_B the resume point inside of that function. The entry of the function has PC_B = 0.
-       s.Sect = sect
-       s.Value = int64(funcValueOffset+va/ld.MINFUNC) << 16 // va starts at zero
+       ldr.SetSymSect(s, sect)
+       ldr.SetSymValue(s, int64(funcValueOffset+va/ld.MINFUNC) << 16) // va starts at zero
        va += uint64(ld.MINFUNC)
        return sect, n, va
 }