Skip to content

Commit e8700f1

Browse files
committed
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 <[email protected]> Run-TryBot: Cherry Zhang <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent 747f426 commit e8700f1

File tree

10 files changed

+39
-2
lines changed

10 files changed

+39
-2
lines changed

src/cmd/compile/internal/objw/objw.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ func SymPtr(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
4646
return off
4747
}
4848

49+
func SymPtrWeak(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
50+
off = int(types.Rnd(int64(off), int64(types.PtrSize)))
51+
s.WriteWeakAddr(base.Ctxt, int64(off), types.PtrSize, x, int64(xoff))
52+
off += types.PtrSize
53+
return off
54+
}
55+
4956
func SymPtrOff(s *obj.LSym, off int, x *obj.LSym) int {
5057
s.WriteOff(base.Ctxt, int64(off), x, 0)
5158
off += 4

src/cmd/compile/internal/reflectdata/reflect.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1338,7 +1338,7 @@ func WriteTabs() {
13381338
o = objw.Uint32(i.lsym, o, types.TypeHash(i.t)) // copy of type hash
13391339
o += 4 // skip unused field
13401340
for _, fn := range genfun(i.t, i.itype) {
1341-
o = objw.SymPtr(i.lsym, o, fn, 0) // method pointer for each method
1341+
o = objw.SymPtrWeak(i.lsym, o, fn, 0) // method pointer for each method
13421342
}
13431343
// Nothing writes static itabs, so they are read only.
13441344
objw.Global(i.lsym, int32(o), int16(obj.DUPOK|obj.RODATA))

src/cmd/internal/obj/data.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64)
135135
s.writeAddr(ctxt, off, siz, rsym, roff, objabi.R_ADDR)
136136
}
137137

138+
// WriteWeakAddr writes an address of size siz into s at offset off.
139+
// rsym and roff specify the relocation for the address.
140+
// This is a weak reference.
141+
func (s *LSym) WriteWeakAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
142+
s.writeAddr(ctxt, off, siz, rsym, roff, objabi.R_WEAKADDR)
143+
}
144+
138145
// WriteCURelativeAddr writes a pointer-sized address into s at offset off.
139146
// rsym and roff specify the relocation for the address which will be
140147
// resolved by the linker to an offset from the DW_AT_low_pc attribute of

src/cmd/internal/objabi/reloctype.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ const (
258258
// reachable.
259259
R_WEAK = -1 << 15
260260

261+
R_WEAKADDR = R_WEAK | R_ADDR
261262
R_WEAKADDROFF = R_WEAK | R_ADDROFF
262263
)
263264

src/cmd/link/internal/ld/data.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
306306
log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
307307
}
308308
case objabi.R_ADDR:
309+
if weak && !ldr.AttrReachable(rs) {
310+
// Redirect it to runtime.unreachableMethod, which will throw if called.
311+
rs = syms.unreachableMethod
312+
}
309313
if target.IsExternal() {
310314
nExtReloc++
311315

@@ -586,6 +590,9 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc) (loa
586590
case objabi.R_ADDR:
587591
// set up addend for eventual relocation via outer symbol.
588592
rs := ldr.ResolveABIAlias(r.Sym())
593+
if r.Weak() && !ldr.AttrReachable(rs) {
594+
rs = ctxt.ArchSyms.unreachableMethod
595+
}
589596
rs, off := FoldSubSymbolOffset(ldr, rs)
590597
rr.Xadd = r.Add() + off
591598
rr.Xsym = rs

src/cmd/link/internal/ld/deadcode.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ func (d *deadcodePass) init() {
6464
}
6565
}
6666
names = append(names, *flagEntrySymbol)
67+
// runtime.unreachableMethod is a function that will throw if called.
68+
// We redirect unreachable methods to it.
69+
names = append(names, "runtime.unreachableMethod")
6770
if !d.ctxt.linkShared && d.ctxt.BuildMode != BuildModePlugin {
6871
// runtime.buildVersion and runtime.modinfo are referenced in .go.buildinfo section
6972
// (see function buildinfo in data.go). They should normally be reachable from the

src/cmd/link/internal/ld/lib.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ type ArchSyms struct {
118118
Dynamic loader.Sym
119119
DynSym loader.Sym
120120
DynStr loader.Sym
121+
122+
unreachableMethod loader.Sym
121123
}
122124

123125
// mkArchSym is a helper for setArchSyms, to set up a special symbol.
@@ -142,6 +144,7 @@ func (ctxt *Link) setArchSyms() {
142144
ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
143145
ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
144146
ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
147+
ctxt.mkArchSym("runtime.unreachableMethod", sym.SymVerABIInternal, &ctxt.unreachableMethod)
145148

146149
if ctxt.IsPPC64() {
147150
ctxt.mkArchSym("TOC", 0, &ctxt.TOC)

src/cmd/link/internal/ld/testdata/deadcode/ifacemethod4.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package main
1010

1111
type T int
1212

13+
//go:noinline
1314
func (T) M() {}
1415

1516
type I interface{ M() }
@@ -20,4 +21,5 @@ var pp *I
2021
func main() {
2122
p = new(T) // use type T
2223
pp = new(I) // use type I
24+
*pp = *p // convert T to I, build itab
2325
}

src/runtime/iface.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,3 +553,10 @@ var staticuint64s = [...]uint64{
553553
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
554554
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
555555
}
556+
557+
// The linker redirects a reference of a method that it determined
558+
// unreachable to a reference to this function, so it will throw if
559+
// ever called.
560+
func unreachableMethod() {
561+
throw("unreachable method called. linker bug?")
562+
}

src/runtime/type.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
262262
if off == -1 {
263263
// -1 is the sentinel value for unreachable code.
264264
// See cmd/link/internal/ld/data.go:relocsym.
265-
return unsafe.Pointer(^uintptr(0))
265+
return unsafe.Pointer(funcPC(unreachableMethod))
266266
}
267267
base := uintptr(unsafe.Pointer(t))
268268
var md *moduledata

0 commit comments

Comments
 (0)