Commit 376ef734 authored by Than McIntosh's avatar Than McIntosh

[dev.link] cmd/link: rework relocation handling in new deadcode

Do a better job of reading relocations in the new deadcode pass.
Specifically, during method type processing, read relocations for the
symbol we're working on into a slice, and then pass the slice to
helper functions, as opposed to rereading relocs at each stage.

Change-Id: I95e3737ae91bb09b4da8e6ee68112ec255ceb0fc
Reviewed-on: https://go-review.googlesource.com/c/go/+/201722
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent fb066098
...@@ -32,6 +32,7 @@ type deadcodePass2 struct { ...@@ -32,6 +32,7 @@ type deadcodePass2 struct {
ctxt *Link ctxt *Link
ldr *loader.Loader ldr *loader.Loader
wq workQueue wq workQueue
rtmp []loader.Reloc
ifaceMethod map[methodsig]bool // methods declared in reached interfaces ifaceMethod map[methodsig]bool // methods declared in reached interfaces
markableMethods []methodref2 // methods of reached types markableMethods []methodref2 // methods of reached types
...@@ -78,9 +79,9 @@ func (d *deadcodePass2) init() { ...@@ -78,9 +79,9 @@ func (d *deadcodePass2) init() {
// but we do keep the symbols it refers to. // but we do keep the symbols it refers to.
exportsIdx := d.ldr.Lookup("go.plugin.exports", 0) exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
if exportsIdx != 0 { if exportsIdx != 0 {
relocs := d.ldr.Relocs(exportsIdx) d.ReadRelocs(exportsIdx)
for i := 0; i < relocs.Count; i++ { for i := 0; i < len(d.rtmp); i++ {
d.mark(relocs.At(i).Sym) d.mark(d.rtmp[i].Sym)
} }
} }
} }
...@@ -103,14 +104,19 @@ func (d *deadcodePass2) init() { ...@@ -103,14 +104,19 @@ func (d *deadcodePass2) init() {
} }
func (d *deadcodePass2) flood() { func (d *deadcodePass2) flood() {
symRelocs := []loader.Reloc{}
for !d.wq.empty() { for !d.wq.empty() {
symIdx := d.wq.pop() symIdx := d.wq.pop()
d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx) d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx)
relocs := d.ldr.Relocs(symIdx)
symRelocs = relocs.ReadAll(symRelocs)
if d.ldr.IsGoType(symIdx) { if d.ldr.IsGoType(symIdx) {
p := d.ldr.Data(symIdx) p := d.ldr.Data(symIdx)
if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface { if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface {
for _, sig := range decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx) { for _, sig := range d.decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx, symRelocs) {
if d.ctxt.Debugvlog > 1 { if d.ctxt.Debugvlog > 1 {
d.ctxt.Logf("reached iface method: %s\n", sig) d.ctxt.Logf("reached iface method: %s\n", sig)
} }
...@@ -120,9 +126,8 @@ func (d *deadcodePass2) flood() { ...@@ -120,9 +126,8 @@ func (d *deadcodePass2) flood() {
} }
var methods []methodref2 var methods []methodref2
relocs := d.ldr.Relocs(symIdx)
for i := 0; i < relocs.Count; i++ { for i := 0; i < relocs.Count; i++ {
r := relocs.At(i) r := symRelocs[i]
if r.Type == objabi.R_WEAKADDROFF { if r.Type == objabi.R_WEAKADDROFF {
continue continue
} }
...@@ -151,7 +156,7 @@ func (d *deadcodePass2) flood() { ...@@ -151,7 +156,7 @@ func (d *deadcodePass2) flood() {
// Decode runtime type information for type methods // Decode runtime type information for type methods
// to help work out which methods can be called // to help work out which methods can be called
// dynamically via interfaces. // dynamically via interfaces.
methodsigs := decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx) methodsigs := d.decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx, symRelocs)
if len(methods) != len(methodsigs) { if len(methods) != len(methodsigs) {
panic(fmt.Sprintf("%q has %d method relocations for %d methods", d.ldr.SymName(symIdx), len(methods), len(methodsigs))) panic(fmt.Sprintf("%q has %d method relocations for %d methods", d.ldr.SymName(symIdx), len(methods), len(methodsigs)))
} }
...@@ -171,10 +176,10 @@ func (d *deadcodePass2) mark(symIdx loader.Sym) { ...@@ -171,10 +176,10 @@ func (d *deadcodePass2) mark(symIdx loader.Sym) {
} }
func (d *deadcodePass2) markMethod(m methodref2) { func (d *deadcodePass2) markMethod(m methodref2) {
relocs := d.ldr.Relocs(m.src) d.ReadRelocs(m.src)
d.mark(relocs.At(m.r).Sym) d.mark(d.rtmp[m.r].Sym)
d.mark(relocs.At(m.r + 1).Sym) d.mark(d.rtmp[m.r+1].Sym)
d.mark(relocs.At(m.r + 2).Sym) d.mark(d.rtmp[m.r+2].Sym)
} }
func deadcode2(ctxt *Link) { func deadcode2(ctxt *Link) {
...@@ -257,12 +262,15 @@ func (m methodref2) isExported() bool { ...@@ -257,12 +262,15 @@ func (m methodref2) isExported() bool {
// the function type. // the function type.
// //
// Conveniently this is the layout of both runtime.method and runtime.imethod. // Conveniently this is the layout of both runtime.method and runtime.imethod.
func decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off, size, count int) []methodsig { func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, off, size, count int) []methodsig {
var buf bytes.Buffer var buf bytes.Buffer
var methods []methodsig var methods []methodsig
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
buf.WriteString(decodetypeName2(ldr, symIdx, off)) buf.WriteString(decodetypeName2(ldr, symIdx, symRelocs, off))
mtypSym := decodeRelocSym2(ldr, symIdx, int32(off+4)) mtypSym := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off+4))
// FIXME: add some sort of caching here, since we may see some of the
// same symbols over time for param types.
d.ReadRelocs(mtypSym)
mp := ldr.Data(mtypSym) mp := ldr.Data(mtypSym)
buf.WriteRune('(') buf.WriteRune('(')
...@@ -271,7 +279,7 @@ func decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off ...@@ -271,7 +279,7 @@ func decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off
if i > 0 { if i > 0 {
buf.WriteString(", ") buf.WriteString(", ")
} }
a := decodetypeFuncInType2(ldr, arch, mtypSym, i) a := d.decodetypeFuncInType2(ldr, arch, mtypSym, d.rtmp, i)
buf.WriteString(ldr.SymName(a)) buf.WriteString(ldr.SymName(a))
} }
buf.WriteString(") (") buf.WriteString(") (")
...@@ -280,7 +288,7 @@ func decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off ...@@ -280,7 +288,7 @@ func decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off
if i > 0 { if i > 0 {
buf.WriteString(", ") buf.WriteString(", ")
} }
a := decodetypeFuncOutType2(ldr, arch, mtypSym, i) a := d.decodetypeFuncOutType2(ldr, arch, mtypSym, d.rtmp, i)
buf.WriteString(ldr.SymName(a)) buf.WriteString(ldr.SymName(a))
} }
buf.WriteRune(')') buf.WriteRune(')')
...@@ -292,12 +300,12 @@ func decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off ...@@ -292,12 +300,12 @@ func decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off
return methods return methods
} }
func decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) []methodsig { func (d *deadcodePass2) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig {
p := ldr.Data(symIdx) p := ldr.Data(symIdx)
if decodetypeKind(arch, p)&kindMask != kindInterface { if decodetypeKind(arch, p)&kindMask != kindInterface {
panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx))) panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx)))
} }
rel := decodeReloc2(ldr, symIdx, int32(commonsize(arch)+arch.PtrSize)) rel := decodeReloc2(ldr, symIdx, symRelocs, int32(commonsize(arch)+arch.PtrSize))
if rel.Sym == 0 { if rel.Sym == 0 {
return nil return nil
} }
...@@ -307,10 +315,10 @@ func decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) ...@@ -307,10 +315,10 @@ func decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym)
off := int(rel.Add) // array of reflect.imethod values off := int(rel.Add) // array of reflect.imethod values
numMethods := int(decodetypeIfaceMethodCount(arch, p)) numMethods := int(decodetypeIfaceMethodCount(arch, p))
sizeofIMethod := 4 + 4 sizeofIMethod := 4 + 4
return decodeMethodSig2(ldr, arch, symIdx, off, sizeofIMethod, numMethods) return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofIMethod, numMethods)
} }
func decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) []methodsig { func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig {
p := ldr.Data(symIdx) p := ldr.Data(symIdx)
if !decodetypeHasUncommon(arch, p) { if !decodetypeHasUncommon(arch, p) {
panic(fmt.Sprintf("no methods on %q", ldr.SymName(symIdx))) panic(fmt.Sprintf("no methods on %q", ldr.SymName(symIdx)))
...@@ -341,13 +349,12 @@ func decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) [ ...@@ -341,13 +349,12 @@ func decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) [
moff := int(decodeInuxi(arch, p[off+4+2+2:], 4)) moff := int(decodeInuxi(arch, p[off+4+2+2:], 4))
off += moff // offset to array of reflect.method values off += moff // offset to array of reflect.method values
const sizeofMethod = 4 * 4 // sizeof reflect.method in program const sizeofMethod = 4 * 4 // sizeof reflect.method in program
return decodeMethodSig2(ldr, arch, symIdx, off, sizeofMethod, mcount) return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofMethod, mcount)
} }
func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, off int32) loader.Reloc { func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Reloc {
relocs := ldr.Relocs(symIdx) for j := 0; j < len(symRelocs); j++ {
for j := 0; j < relocs.Count; j++ { rel := symRelocs[j]
rel := relocs.At(j)
if rel.Off == off { if rel.Off == off {
return rel return rel
} }
...@@ -355,13 +362,13 @@ func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, off int32) loader.Reloc ...@@ -355,13 +362,13 @@ func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, off int32) loader.Reloc
return loader.Reloc{} return loader.Reloc{}
} }
func decodeRelocSym2(ldr *loader.Loader, symIdx loader.Sym, off int32) loader.Sym { func decodeRelocSym2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Sym {
return decodeReloc2(ldr, symIdx, off).Sym return decodeReloc2(ldr, symIdx, symRelocs, off).Sym
} }
// decodetypeName2 decodes the name from a reflect.name. // decodetypeName2 decodes the name from a reflect.name.
func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, off int) string { func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int) string {
r := decodeRelocSym2(ldr, symIdx, int32(off)) r := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off))
if r == 0 { if r == 0 {
return "" return ""
} }
...@@ -371,7 +378,7 @@ func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, off int) string { ...@@ -371,7 +378,7 @@ func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, off int) string {
return string(data[3 : 3+namelen]) return string(data[3 : 3+namelen])
} }
func decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) loader.Sym { func (d *deadcodePass2) decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
uadd := commonsize(arch) + 4 uadd := commonsize(arch) + 4
if arch.PtrSize == 8 { if arch.PtrSize == 8 {
uadd += 4 uadd += 4
...@@ -379,9 +386,17 @@ func decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym ...@@ -379,9 +386,17 @@ func decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym
if decodetypeHasUncommon(arch, ldr.Data(symIdx)) { if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
uadd += uncommonSize() uadd += uncommonSize()
} }
return decodeRelocSym2(ldr, symIdx, int32(uadd+i*arch.PtrSize)) return decodeRelocSym2(ldr, symIdx, symRelocs, int32(uadd+i*arch.PtrSize))
}
func (d *deadcodePass2) decodetypeFuncOutType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
return d.decodetypeFuncInType2(ldr, arch, symIdx, symRelocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
} }
func decodetypeFuncOutType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) loader.Sym { // readRelocs reads the relocations for the specified symbol into the
return decodetypeFuncInType2(ldr, arch, symIdx, i+decodetypeFuncInCount(arch, ldr.Data(symIdx))) // deadcode relocs work array. Use with care, since the work array
// is a singleton.
func (d *deadcodePass2) ReadRelocs(symIdx loader.Sym) {
relocs := d.ldr.Relocs(symIdx)
d.rtmp = relocs.ReadAll(d.rtmp)
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment