return off
}
+func SymPtrWeak(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
+ off = int(types.Rnd(int64(off), int64(types.PtrSize)))
+ s.WriteWeakAddr(base.Ctxt, int64(off), types.PtrSize, x, int64(xoff))
+ off += types.PtrSize
+ return off
+}
+
func SymPtrOff(s *obj.LSym, off int, x *obj.LSym) int {
s.WriteOff(base.Ctxt, int64(off), x, 0)
off += 4
o = objw.Uint32(i.lsym, o, types.TypeHash(i.t)) // copy of type hash
o += 4 // skip unused field
for _, fn := range genfun(i.t, i.itype) {
- o = objw.SymPtr(i.lsym, o, fn, 0) // method pointer for each method
+ o = objw.SymPtrWeak(i.lsym, o, fn, 0) // method pointer for each method
}
// Nothing writes static itabs, so they are read only.
objw.Global(i.lsym, int32(o), int16(obj.DUPOK|obj.RODATA))
s.writeAddr(ctxt, off, siz, rsym, roff, objabi.R_ADDR)
}
+// WriteWeakAddr writes an address of size siz into s at offset off.
+// rsym and roff specify the relocation for the address.
+// This is a weak reference.
+func (s *LSym) WriteWeakAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
+ s.writeAddr(ctxt, off, siz, rsym, roff, objabi.R_WEAKADDR)
+}
+
// WriteCURelativeAddr writes a pointer-sized address into s at offset off.
// rsym and roff specify the relocation for the address which will be
// resolved by the linker to an offset from the DW_AT_low_pc attribute of
// reachable.
R_WEAK = -1 << 15
+ R_WEAKADDR = R_WEAK | R_ADDR
R_WEAKADDROFF = R_WEAK | R_ADDROFF
)
log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
}
case objabi.R_ADDR:
+ if weak && !ldr.AttrReachable(rs) {
+ // Redirect it to runtime.unreachableMethod, which will throw if called.
+ rs = syms.unreachableMethod
+ }
if target.IsExternal() {
nExtReloc++
case objabi.R_ADDR:
// set up addend for eventual relocation via outer symbol.
rs := ldr.ResolveABIAlias(r.Sym())
+ if r.Weak() && !ldr.AttrReachable(rs) {
+ rs = ctxt.ArchSyms.unreachableMethod
+ }
rs, off := FoldSubSymbolOffset(ldr, rs)
rr.Xadd = r.Add() + off
rr.Xsym = rs
}
}
names = append(names, *flagEntrySymbol)
+ // runtime.unreachableMethod is a function that will throw if called.
+ // We redirect unreachable methods to it.
+ names = append(names, "runtime.unreachableMethod")
if !d.ctxt.linkShared && d.ctxt.BuildMode != BuildModePlugin {
// runtime.buildVersion and runtime.modinfo are referenced in .go.buildinfo section
// (see function buildinfo in data.go). They should normally be reachable from the
Dynamic loader.Sym
DynSym loader.Sym
DynStr loader.Sym
+
+ unreachableMethod loader.Sym
}
// mkArchSym is a helper for setArchSyms, to set up a special symbol.
ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
+ ctxt.mkArchSym("runtime.unreachableMethod", sym.SymVerABIInternal, &ctxt.unreachableMethod)
if ctxt.IsPPC64() {
ctxt.mkArchSym("TOC", 0, &ctxt.TOC)
type T int
+//go:noinline
func (T) M() {}
type I interface{ M() }
func main() {
p = new(T) // use type T
pp = new(I) // use type I
+ *pp = *p // convert T to I, build itab
}
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
}
+
+// The linker redirects a reference of a method that it determined
+// unreachable to a reference to this function, so it will throw if
+// ever called.
+func unreachableMethod() {
+ throw("unreachable method called. linker bug?")
+}
if off == -1 {
// -1 is the sentinel value for unreachable code.
// See cmd/link/internal/ld/data.go:relocsym.
- return unsafe.Pointer(^uintptr(0))
+ return unsafe.Pointer(funcPC(unreachableMethod))
}
base := uintptr(unsafe.Pointer(t))
var md *moduledata