}
// 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
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) {
// 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 {
}
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++
}
}
// 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.
continue
}
- thearch.Trampoline(ctxt, r, s)
+ thearch.Trampoline(ctxt, ldr, ri, rs, s)
}
}
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
// 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
}
}
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
// 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)))
}
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
}
// 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())
}
}
// 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
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 (
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
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")
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.*
relocs []goobj2.Reloc2
reltypes []objabi.RelocType // relocation types
data []byte
+ auxs []goobj2.Aux2
}
const (
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.
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)...)
}
}
}
}
+// 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.
// 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 {
// 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
}
}
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))
}
if dupok {
lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(gi))
+ continue
}
lib.Textp2 = append(lib.Textp2, sym.LoaderSym(gi))
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.
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()
}
// 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
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
// 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
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) {
"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")
// 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
}