mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile, cmd/link: use weak reference in itab
When converting a type T to a non-empty interface I, we build the itab which contains the code pointers of the methods. Currently, this brings those methods live (if the itab is live), even if the interface method is never used. This CL changes the itab to use weak references, so the methods can be pruned if not otherwise live. Fixes #42421. Change-Id: Iee5de2ba11d603c5a102a2ba60440d839a7f9702 Reviewed-on: https://go-review.googlesource.com/c/go/+/268479 Trust: Cherry Zhang <cherryyz@google.com> Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
747f426944
commit
e8700f1ce6
10 changed files with 39 additions and 2 deletions
|
|
@ -46,6 +46,13 @@ func SymPtr(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -1338,7 +1338,7 @@ func WriteTabs() {
|
|||
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))
|
||||
|
|
|
|||
|
|
@ -135,6 +135,13 @@ func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64)
|
|||
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
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ const (
|
|||
// reachable.
|
||||
R_WEAK = -1 << 15
|
||||
|
||||
R_WEAKADDR = R_WEAK | R_ADDR
|
||||
R_WEAKADDROFF = R_WEAK | R_ADDROFF
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -306,6 +306,10 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
|
|||
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++
|
||||
|
||||
|
|
@ -586,6 +590,9 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc) (loa
|
|||
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
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ func (d *deadcodePass) init() {
|
|||
}
|
||||
}
|
||||
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
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ type ArchSyms struct {
|
|||
Dynamic loader.Sym
|
||||
DynSym loader.Sym
|
||||
DynStr loader.Sym
|
||||
|
||||
unreachableMethod loader.Sym
|
||||
}
|
||||
|
||||
// mkArchSym is a helper for setArchSyms, to set up a special symbol.
|
||||
|
|
@ -142,6 +144,7 @@ func (ctxt *Link) setArchSyms() {
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package main
|
|||
|
||||
type T int
|
||||
|
||||
//go:noinline
|
||||
func (T) M() {}
|
||||
|
||||
type I interface{ M() }
|
||||
|
|
@ -20,4 +21,5 @@ var pp *I
|
|||
func main() {
|
||||
p = new(T) // use type T
|
||||
pp = new(I) // use type I
|
||||
*pp = *p // convert T to I, build itab
|
||||
}
|
||||
|
|
|
|||
|
|
@ -553,3 +553,10 @@ var staticuint64s = [...]uint64{
|
|||
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?")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
|
|||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue