}
+// foldSubSymbolOffset computes the offset of symbol s to its top-level outer
+// symbol. Returns the top-level symbol and the offset.
+// This is used in generating external relocations.
+func foldSubSymbolOffset(ldr *loader.Loader, s loader.Sym) (loader.Sym, int64) {
+ outer := ldr.OuterSym(s)
+ off := int64(0)
+ for outer != 0 {
+ off += ldr.SymValue(s) - ldr.SymValue(outer)
+ s = outer
+ outer = ldr.OuterSym(s)
+ }
+ return s, off
+}
+
// relocsym resolve relocations in "s", updating the symbol's content
// in "P".
// The main loop walks through the list of relocations attached to "s"
if relocs.Count() == 0 {
return
}
+ var extRelocs []loader.ExtReloc
for ri := 0; ri < relocs.Count(); ri++ {
r := relocs.At2(ri)
off := r.Off()
err.Errorf(s, "unreachable sym in relocation: %s", ldr.SymName(rs))
}
+ var rr loader.ExtReloc
+ needExtReloc := false // will set to true below in case it is needed
if target.IsExternal() {
- panic("external linking not implemented")
- //r.InitExt()
+ rr.Sym = rs
+ rr.Type = rt
+ rr.Off = off
+ rr.Siz = uint8(siz)
+ rr.Add = r.Add()
}
// TODO(mundaym): remove this special case - see issue 14218.
err.Errorf(s, "unknown reloc to %v: %d (%s)", ldr.SymName(rs), rt, sym.RelocName(target.Arch, rt))
}
case objabi.R_TLS_LE:
- //if target.IsExternal() && target.IsElf() {
- // r.Done = false
- // if r.Sym == nil {
- // r.Sym = syms.Tlsg
- // }
- // r.Xsym = r.Sym
- // r.Xadd = r.Add
- // o = 0
- // if !target.IsAMD64() {
- // o = r.Add
- // }
- // break
- //}
+ if target.IsExternal() && target.IsElf() {
+ needExtReloc = true
+ if rr.Sym == 0 {
+ rr.Sym = syms.Tlsg2
+ }
+ rr.Xsym = rr.Sym
+ rr.Xadd = rr.Add
+ o = 0
+ if !target.IsAMD64() {
+ o = rr.Add
+ }
+ break
+ }
if target.IsElf() && target.IsARM() {
// On ELF ARM, the thread pointer is 8 bytes before
log.Fatalf("unexpected R_TLS_LE relocation for %v", target.HeadType)
}
case objabi.R_TLS_IE:
- //if target.IsExternal() && target.IsElf() {
- // r.Done = false
- // if r.Sym == nil {
- // r.Sym = syms.Tlsg
- // }
- // r.Xsym = r.Sym
- // r.Xadd = r.Add
- // o = 0
- // if !target.IsAMD64() {
- // o = r.Add
- // }
- // break
- //}
+ if target.IsExternal() && target.IsElf() {
+ needExtReloc = true
+ if rr.Sym == 0 {
+ rr.Sym = syms.Tlsg2
+ }
+ rr.Xsym = rr.Sym
+ rr.Xadd = rr.Add
+ o = 0
+ if !target.IsAMD64() {
+ o = rr.Add
+ }
+ break
+ }
if target.IsPIE() && target.IsElf() {
// We are linking the final executable, so we
// can optimize any TLS IE relocation to LE.
log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
}
case objabi.R_ADDR:
- //if target.IsExternal() && r.Sym.Type != sym.SCONST {
- // r.Done = false
- //
- // // set up addend for eventual relocation via outer symbol.
- // rs := r.Sym
- //
- // r.Xadd = r.Add
- // for rs.Outer != nil {
- // r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
- // rs = rs.Outer
- // }
- //
- // if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
- // Errorf(s, "missing section for relocation target %s", rs.Name)
- // }
- // r.Xsym = rs
- //
- // o = r.Xadd
- // if target.IsElf() {
- // if target.IsAMD64() {
- // o = 0
- // }
- // } else if target.IsDarwin() {
- // if rs.Type != sym.SHOSTOBJ {
- // o += Symaddr(rs)
- // }
- // } else if target.IsWindows() {
- // // nothing to do
- // } else if target.IsAIX() {
- // o = Symaddr(r.Sym) + r.Add
- // } else {
- // Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
- // }
- //
- // break
- //}
+ if target.IsExternal() && rst != sym.SCONST {
+ needExtReloc = true
+
+ // set up addend for eventual relocation via outer symbol.
+ rs := rs
+ rs, off := foldSubSymbolOffset(ldr, rs)
+ rr.Xadd = rr.Add + off
+ rst := ldr.SymType(rs)
+ if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && rst != sym.SUNDEFEXT && ldr.SymSect(rs) == nil {
+ err.Errorf(s, "missing section for relocation target %s", ldr.SymName(rs))
+ }
+ rr.Xsym = rs
+
+ o = rr.Xadd
+ if target.IsElf() {
+ if target.IsAMD64() {
+ o = 0
+ }
+ } else if target.IsDarwin() {
+ if ldr.SymType(rs) != sym.SHOSTOBJ {
+ o += ldr.SymValue(rs)
+ }
+ } else if target.IsWindows() {
+ // nothing to do
+ } else if target.IsAIX() {
+ o = ldr.SymValue(rr.Sym) + rr.Add
+ } else {
+ err.Errorf(s, "unhandled pcrel relocation to %s on %v", ldr.SymName(rs), target.HeadType)
+ }
+
+ break
+ }
// On AIX, a second relocation must be done by the loader,
// as section addresses can change once loaded.
// symbol which isn't in .data. However, as .text has the
// same address once loaded, this is possible.
if ldr.SymSect(s).Seg == &Segdata {
+ panic("not implemented")
//Xcoffadddynrel(target, ldr, err, s, &r) // XXX
}
}
err.Errorf(s, "missing DWARF section for relocation target %s", ldr.SymName(rs))
}
- //if target.IsExternal() {
- // r.Done = false
- //
- // // On most platforms, the external linker needs to adjust DWARF references
- // // as it combines DWARF sections. However, on Darwin, dsymutil does the
- // // DWARF linking, and it understands how to follow section offsets.
- // // Leaving in the relocation records confuses it (see
- // // https://golang.org/issue/22068) so drop them for Darwin.
- // if target.IsDarwin() {
- // r.Done = true
- // }
- //
- // // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
- // // for R_DWARFSECREF relocations, while R_ADDR is replaced with
- // // IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32.
- // // Do not replace R_DWARFSECREF with R_ADDR for windows -
- // // let PE code emit correct relocations.
- // if !target.IsWindows() {
- // r.Type = objabi.R_ADDR
- // }
- //
- // r.Xsym = r.Sym.Sect.Sym
- // r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
- //
- // o = r.Xadd
- // if target.IsElf() && target.IsAMD64() {
- // o = 0
- // }
- // break
- //}
+ if target.IsExternal() {
+ needExtReloc = true
+
+ // On most platforms, the external linker needs to adjust DWARF references
+ // as it combines DWARF sections. However, on Darwin, dsymutil does the
+ // DWARF linking, and it understands how to follow section offsets.
+ // Leaving in the relocation records confuses it (see
+ // https://golang.org/issue/22068) so drop them for Darwin.
+ if target.IsDarwin() {
+ needExtReloc = false
+ }
+
+ // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
+ // for R_DWARFSECREF relocations, while R_ADDR is replaced with
+ // IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32.
+ // Do not replace R_DWARFSECREF with R_ADDR for windows -
+ // let PE code emit correct relocations.
+ if !target.IsWindows() {
+ rr.Type = objabi.R_ADDR
+ }
+
+ rr.Xsym = loader.Sym(ldr.SymSect(rr.Sym).Sym2)
+ rr.Xadd = rr.Add + ldr.SymValue(rr.Sym) - int64(ldr.SymSect(rr.Sym).Vaddr)
+
+ o = rr.Xadd
+ if target.IsElf() && target.IsAMD64() {
+ o = 0
+ }
+ break
+ }
o = ldr.SymValue(rs) + r.Add() - int64(ldr.SymSect(rs).Vaddr)
case objabi.R_WEAKADDROFF, objabi.R_METHODOFF:
if !ldr.AttrReachable(rs) {
// r.Sym() can be 0 when CALL $(constant) is transformed from absolute PC to relative PC call.
case objabi.R_GOTPCREL:
- //if target.IsDynlinkingGo() && target.IsDarwin() && r.Sym != nil && r.Sym.Type != sym.SCONST {
- // r.Done = false
- // r.Xadd = r.Add
- // r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
- // r.Xsym = r.Sym
- //
- // o = r.Xadd
- // o += int64(r.Siz)
- // break
- //}
+ if target.IsDynlinkingGo() && target.IsDarwin() && rs != 0 && rst != sym.SCONST {
+ needExtReloc = true
+ rr.Xadd = rr.Add
+ rr.Xadd -= int64(rr.Siz) // relative to address after the relocated chunk
+ rr.Xsym = rr.Sym
+
+ o = rr.Xadd
+ o += int64(rr.Siz)
+ break
+ }
fallthrough
case objabi.R_CALL, objabi.R_PCREL:
- //if target.IsExternal() && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
- // // pass through to the external linker.
- // r.Done = false
- // r.Xadd = 0
- // if target.IsElf() {
- // r.Xadd -= int64(r.Siz)
- // }
- // r.Xsym = r.Sym
- // o = 0
- // break
- //}
- //if target.IsExternal() && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
- // r.Done = false
- //
- // // set up addend for eventual relocation via outer symbol.
- // rs := r.Sym
- //
- // r.Xadd = r.Add
- // for rs.Outer != nil {
- // r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
- // rs = rs.Outer
- // }
- //
- // r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
- // if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
- // Errorf(s, "missing section for relocation target %s", rs.Name)
- // }
- // r.Xsym = rs
- //
- // o = r.Xadd
- // if target.IsElf() {
- // if target.IsAMD64() {
- // o = 0
- // }
- // } else if target.IsDarwin() {
- // if r.Type == objabi.R_CALL {
- // if target.IsExternal() && rs.Type == sym.SDYNIMPORT {
- // if target.IsAMD64() {
- // // AMD64 dynamic relocations are relative to the end of the relocation.
- // o += int64(r.Siz)
- // }
- // } else {
- // if rs.Type != sym.SHOSTOBJ {
- // o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
- // }
- // o -= int64(r.Off) // relative to section offset, not symbol
- // }
- // } else {
- // o += int64(r.Siz)
- // }
- // } else if target.IsWindows() && target.IsAMD64() { // only amd64 needs PCREL
- // // PE/COFF's PC32 relocation uses the address after the relocated
- // // bytes as the base. Compensate by skewing the addend.
- // o += int64(r.Siz)
- // } else {
- // Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
- // }
- //
- // break
- //}
+ if target.IsExternal() && rs != 0 && rst == sym.SUNDEFEXT {
+ // pass through to the external linker.
+ needExtReloc = true
+ rr.Xadd = 0
+ if target.IsElf() {
+ rr.Xadd -= int64(rr.Siz)
+ }
+ rr.Xsym = rr.Sym
+ o = 0
+ break
+ }
+ if target.IsExternal() && rs != 0 && rst != sym.SCONST && (ldr.SymSect(rs) != ldr.SymSect(s) || rt == objabi.R_GOTPCREL) {
+ needExtReloc = true
+
+ // set up addend for eventual relocation via outer symbol.
+ rs := rs
+ rs, off := foldSubSymbolOffset(ldr, rs)
+ rr.Xadd = rr.Add + off
+ rr.Xadd -= int64(rr.Siz) // relative to address after the relocated chunk
+ rst := ldr.SymType(rs)
+ if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
+ err.Errorf(s, "missing section for relocation target %s", ldr.SymName(rs))
+ }
+ rr.Xsym = rs
+
+ o = rr.Xadd
+ if target.IsElf() {
+ if target.IsAMD64() {
+ o = 0
+ }
+ } else if target.IsDarwin() {
+ if rr.Type == objabi.R_CALL {
+ if target.IsExternal() && rst == sym.SDYNIMPORT {
+ if target.IsAMD64() {
+ // AMD64 dynamic relocations are relative to the end of the relocation.
+ o += int64(rr.Siz)
+ }
+ } else {
+ if rst != sym.SHOSTOBJ {
+ o += int64(uint64(ldr.SymValue(rs)) - ldr.SymSect(rs).Vaddr)
+ }
+ o -= int64(rr.Off) // relative to section offset, not symbol
+ }
+ } else {
+ o += int64(rr.Siz)
+ }
+ } else if target.IsWindows() && target.IsAMD64() { // only amd64 needs PCREL
+ // PE/COFF's PC32 relocation uses the address after the relocated
+ // bytes as the base. Compensate by skewing the addend.
+ o += int64(rr.Siz)
+ } else {
+ err.Errorf(s, "unhandled pcrel relocation to %s on %v", ldr.SymName(rs), target.HeadType)
+ }
+
+ break
+ }
o = 0
if rs != 0 {
if !target.IsExternal() {
err.Errorf(s, "find XCOFF R_REF with internal linking")
}
- //r.Xsym = r.Sym
- //r.Xadd = r.Add
- //r.Done = false
+ needExtReloc = true
+ rr.Xsym = rr.Sym
+ rr.Xadd = rr.Add
// This isn't a real relocation so it must not update
// its offset value.
case 8:
target.Arch.ByteOrder.PutUint64(P[off:], uint64(o))
}
+
+ if needExtReloc {
+ extRelocs = append(extRelocs, rr)
+ }
+ }
+ if len(extRelocs) != 0 {
+ ldr.SetExtRelocs(s, extRelocs)
}
}
ldr := ctxt.loader
reporter := &ctxt.ErrorReporter
syms := &ctxt.ArchSyms
+ if ctxt.IsExternal() {
+ ldr.InitExtRelocs()
+ }
wg.Add(3)
go func() {
if !ctxt.IsWasm() { // On Wasm, text relocations are applied in Asmb2.
Sym Sym // global index of symbol the reloc addresses
}
+// ExtReloc contains the payload for an external relocation.
+type ExtReloc struct {
+ Off int32 // offset to rewrite
+ Siz uint8 // number of bytes to rewrite: 0, 1, 2, or 4
+ Type objabi.RelocType // the relocation type
+ Sym Sym // global index of symbol the reloc addresses
+ Add int64 // addend
+ Xsym Sym
+ Xadd int64
+}
+
// Reloc2 holds a "handle" to access a relocation record from an
// object file.
type Reloc2 struct {
sects []*sym.Section // sections
symSects []uint16 // symbol's section, index to sects array
- outdata [][]byte // symbol's data in the output buffer
+ outdata [][]byte // symbol's data in the output buffer
+ extRelocs [][]ExtReloc // symbol's external relocations
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
l.outdata = make([][]byte, l.extStart)
}
+// SetExtRelocs sets the section of the i-th symbol. i is global index.
+func (l *Loader) SetExtRelocs(i Sym, relocs []ExtReloc) {
+ l.extRelocs[i] = relocs
+}
+
+// InitExtRelocs initialize the slice used to store external relocations.
+func (l *Loader) InitExtRelocs() {
+ l.extRelocs = make([][]ExtReloc, l.NSym())
+}
+
// SymAlign returns the alignment for a symbol.
func (l *Loader) SymAlign(i Sym) int32 {
// If an alignment has been recorded, return that.
l.convertRelocations(i, &relocs, s, false)
}
+ l.convertExtRelocs(s, i)
+
// Copy data
s.P = pp.data
l.convertRelocations(gi, &relocs, s, false)
}
+ l.convertExtRelocs(s, gi)
+
// Aux symbol info
auxs := r.Auxs(i)
for j := range auxs {
}
}
+// Convert external relocations to sym.Relocs on symbol dst.
+func (l *Loader) convertExtRelocs(dst *sym.Symbol, src Sym) {
+ if int(src) >= len(l.extRelocs) {
+ return
+ }
+ relocs := l.extRelocs[src]
+ if len(relocs) == 0 {
+ return
+ }
+ if len(dst.R) != 0 {
+ panic("bad")
+ }
+ dst.R = make([]sym.Reloc, len(relocs))
+ for i := range dst.R {
+ sr := &relocs[i]
+ r := &dst.R[i]
+ r.InitExt()
+ r.Off = sr.Off
+ r.Siz = sr.Siz
+ r.Type = sr.Type
+ r.Sym = l.Syms[sr.Sym]
+ r.Add = sr.Add
+ r.Xsym = l.Syms[sr.Xsym]
+ r.Xadd = sr.Xadd
+ }
+}
+
// relocId is essentially a <S,R> tuple identifying the Rth
// relocation of symbol S.
type relocId struct {