]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile, cmd/link: use weak reference in itab
authorCherry Zhang <cherryyz@google.com>
Sun, 8 Nov 2020 20:18:35 +0000 (15:18 -0500)
committerCherry Zhang <cherryyz@google.com>
Wed, 24 Mar 2021 14:38:53 +0000 (14:38 +0000)
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>
src/cmd/compile/internal/objw/objw.go
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/internal/obj/data.go
src/cmd/internal/objabi/reloctype.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/deadcode.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/testdata/deadcode/ifacemethod4.go
src/runtime/iface.go
src/runtime/type.go

index 50ce7b747db60a58a4d426e6cdd448e637ddcad5..ed5ad754d9b29f2e2e6c8cdd56655080c777e8f7 100644 (file)
@@ -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
index 0e1de358876160426c4db3a5bb4b2edb0baeb40a..4c974ea3243a3b635591a7c0a0002660bacd928a 100644 (file)
@@ -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))
index f32e07acfed1640173e6ac1314592ef689bae2ad..bcba53c3a4b415482afddcb9d7205ce9def30649 100644 (file)
@@ -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
index 217d8565f27a7677826865958510c5aa87977b57..b241127b4e64b4c76a6637d058fa07ddecd1ffff 100644 (file)
@@ -258,6 +258,7 @@ const (
        // reachable.
        R_WEAK = -1 << 15
 
+       R_WEAKADDR    = R_WEAK | R_ADDR
        R_WEAKADDROFF = R_WEAK | R_ADDROFF
 )
 
index 6de2d893aec606fb2ca8173920a1d5fa14a548cb..b909526de8d478284ae624d58ca55b7c6adb9cd2 100644 (file)
@@ -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
index 33468b429c7c99e43362790f1a10a0d16462b1b8..9b04e2cddc144648a610c9447cb292e426937c6a 100644 (file)
@@ -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
index d136cbad801f0ced4229b2e0c38811d40b18f7d3..c80c29a6a851d8f2aa8032241faf0549c90ec9c0 100644 (file)
@@ -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)
index 52ee2e3d860fa2bd2b19e719ccee52be75fc2eed..4af47ad1fa53eccb792aff52ad9e9ea6a46ce77a 100644 (file)
@@ -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
 }
index 02b18dabff2690249f06f1af5c26ab215f3843e0..cd5fead9990cbfe2c98cfd291620c16b14f59589 100644 (file)
@@ -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?")
+}
index 18fc4bbfad7546a7a78b58a0c2e2259665a864f7..c0911b1dcb1b270bc683ddf76beacae4942727a3 100644 (file)
@@ -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