From 850c602ed62fb36430b872f31ac86142d8eaa5f3 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 6 Apr 2020 15:58:21 -0400 Subject: [PATCH] [dev.link] cmd/link: convert text address assignment to new style 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 --- src/cmd/link/internal/arm/asm.go | 142 ++++++++-------- src/cmd/link/internal/ld/data.go | 152 ++++++++++-------- src/cmd/link/internal/ld/lib.go | 7 +- src/cmd/link/internal/ld/link.go | 2 +- src/cmd/link/internal/ld/main.go | 5 +- src/cmd/link/internal/loader/loader.go | 45 +++++- src/cmd/link/internal/loader/symbolbuilder.go | 3 +- src/cmd/link/internal/ppc64/asm.go | 103 ++++++------ src/cmd/link/internal/wasm/asm.go | 6 +- 9 files changed, 270 insertions(+), 195 deletions(-) diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index bb0ddf9878..18fc54a7e2 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -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) { diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 7c4b08a805..3a1f355056 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -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()) } } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index f16de043ef..e560fea2f1 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -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 ( diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 24866d8e8c..a2ea34ea22 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -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 diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 3b2fd0b659..b91a195694 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -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") diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 32386ccbc0..3437b42b65 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -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)) diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go index cb7dd1cb3c..3d5dc87616 100644 --- a/src/cmd/link/internal/loader/symbolbuilder.go +++ b/src/cmd/link/internal/loader/symbolbuilder.go @@ -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() diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index cb9328d6b2..bc090c8e7c 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -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) { diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go index 6af52b46ff..4367decba5 100644 --- a/src/cmd/link/internal/wasm/asm.go +++ b/src/cmd/link/internal/wasm/asm.go @@ -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 } -- 2.50.0