// set up addend for eventual relocation via outer symbol.
rs, off := ld.FoldSubSymbolOffset(ldr, rs)
- rr.Xadd = r.Add() + off
+ xadd := r.Add() + off
rst := ldr.SymType(rs)
if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
}
- rr.Xsym = rs
nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1
- if target.IsDarwin() && rt == objabi.R_ADDRARM64 && rr.Xadd != 0 {
+ if target.IsDarwin() && rt == objabi.R_ADDRARM64 && xadd != 0 {
nExtReloc = 4 // need another two relocations for non-zero addend
}
// can only encode 24-bit of signed addend, but the instructions
// supports 33-bit of signed addend, so we always encode the
// addend in place.
- o0 |= (uint32((rr.Xadd>>12)&3) << 29) | (uint32((rr.Xadd>>12>>2)&0x7ffff) << 5)
- o1 |= uint32(rr.Xadd&0xfff) << 10
- rr.Xadd = 0
+ o0 |= (uint32((xadd>>12)&3) << 29) | (uint32((xadd>>12>>2)&0x7ffff) << 5)
+ o1 |= uint32(xadd&0xfff) << 10
// when laid out, the instruction order must always be o1, o2.
if target.IsBigEndian() {
if rt == objabi.R_ARM64_TLS_IE {
nExtReloc = 2 // need two ELF relocations. see elfreloc1
}
- rr.Xsym = rs
- rr.Xadd = r.Add()
return val, nExtReloc, isOk
}
}
return -1
}
+func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc2, s loader.Sym) (loader.ExtReloc, bool) {
+ rs := ldr.ResolveABIAlias(r.Sym())
+ var rr loader.ExtReloc
+ switch rt := r.Type(); rt {
+ case objabi.R_ARM64_GOTPCREL,
+ objabi.R_ADDRARM64:
+
+ // set up addend for eventual relocation via outer symbol.
+ rs, off := ld.FoldSubSymbolOffset(ldr, rs)
+ rr.Xadd = r.Add() + off
+ rr.Xsym = rs
+
+ // Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
+ // will make the linking fail because it thinks the code is not PIC even though
+ // the BR26 relocation should be fully resolved at link time.
+ // That is the reason why the next if block is disabled. When the bug in ld64
+ // is fixed, we can enable this block and also enable duff's device in cmd/7g.
+ if false && target.IsDarwin() {
+ // Mach-O wants the addend to be encoded in the instruction
+ // Note that although Mach-O supports ARM64_RELOC_ADDEND, it
+ // can only encode 24-bit of signed addend, but the instructions
+ // supports 33-bit of signed addend, so we always encode the
+ // addend in place.
+ rr.Xadd = 0
+ }
+ return rr, true
+ case objabi.R_CALLARM64,
+ objabi.R_ARM64_TLS_LE,
+ objabi.R_ARM64_TLS_IE:
+ rr.Xsym = rs
+ rr.Xadd = r.Add()
+ return rr, true
+ }
+ return rr, false
+}
+
func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
if plt.Size() == 0 {
// stp x16, x30, [sp, #-16]!
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
+ Extreloc: extreloc,
Elfreloc1: elfreloc1,
ElfrelocSize: 24,
Elfsetupplt: elfsetupplt,
o = int64(target.Arch.ByteOrder.Uint64(P[off:]))
}
var rp *loader.ExtReloc
- if target.IsExternal() {
+ if target.IsExternal() && !target.StreamExtRelocs() {
// Don't pass &rr directly to Archreloc, which will escape rr
// even if this case is not taken. Instead, as Archreloc will
// likely return true, we speculatively add rr to extRelocs
}
out, nExtReloc, ok := thearch.Archreloc(target, ldr, syms, r, rp, s, o)
if target.IsExternal() {
- if nExtReloc == 0 {
- // No external relocation needed. Speculation failed. Undo the append.
- extRelocs = extRelocs[:len(extRelocs)-1]
+ if target.StreamExtRelocs() {
+ extraExtReloc += nExtReloc
} else {
- // Account for the difference between host relocations and Go relocations.
- extraExtReloc += nExtReloc - 1
+ if nExtReloc == 0 {
+ // No external relocation needed. Speculation failed. Undo the append.
+ extRelocs = extRelocs[:len(extRelocs)-1]
+ } else {
+ // Account for the difference between host relocations and Go relocations.
+ extraExtReloc += nExtReloc - 1
+ }
}
}
needExtReloc = false // already appended
switch rt {
default:
- // TODO: handle arch-specific relocations
- panic("unsupported")
+ return thearch.Extreloc(&target, ldr, r, s)
case objabi.R_TLS_LE, objabi.R_TLS_IE:
if target.IsElf() {
Asmb func(*Link, *loader.Loader)
Asmb2 func(*Link, *loader.Loader)
+ // Extreloc is an arch-specific hook that converts a Go relocation to an
+ // external relocation. Return the external relocation and whether it is
+ // needed.
+ Extreloc func(*Target, *loader.Loader, loader.Reloc2, loader.Sym) (loader.ExtReloc, bool)
+
Elfreloc1 func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtRelocView, int64) bool
ElfrelocSize uint32 // size of an ELF relocation record, must match Elfreloc1.
Elfsetupplt func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
if ldr.SymValue(s) >= int64(eaddr) {
break
}
- relocs := ldr.ExtRelocs(s)
+
+ // Compute external relocations on the go, and pass to Machoreloc1
+ // to stream out.
+ relocs := ldr.Relocs(s)
for ri := 0; ri < relocs.Count(); ri++ {
- r := relocs.At(ri)
- if r.Xsym == 0 {
+ r := relocs.At2(ri)
+ rr, ok := extreloc(ctxt, ldr, s, r, ri)
+ if !ok {
+ continue
+ }
+ if rr.Xsym == 0 {
ldr.Errorf(s, "missing xsym in relocation")
continue
}
- if !ldr.AttrReachable(r.Xsym) {
- ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(r.Xsym))
+ if !ldr.AttrReachable(rr.Xsym) {
+ ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
}
- if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, r, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
+ rv := loader.ExtRelocView{Reloc2: r, ExtReloc: rr}
+ if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rv, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
ldr.Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), r.Siz(), ldr.SymName(r.Sym()))
}
}
// Temporary helper.
func (t *Target) StreamExtRelocs() bool {
- return t.IsELF && (t.IsAMD64() || t.Is386())
+ return (t.IsELF || t.IsDarwin()) && (t.IsAMD64() || t.Is386() || t.IsARM64())
}