Source file src/pkg/cmd/link/internal/ld/deadcode.go
1
2
3
4
5 package ld
6
7 import (
8 "cmd/internal/objabi"
9 "cmd/internal/sys"
10 "cmd/link/internal/sym"
11 "fmt"
12 "strings"
13 "unicode"
14 )
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 func deadcode(ctxt *Link) {
49 if ctxt.Debugvlog != 0 {
50 ctxt.Logf("%5.2f deadcode\n", Cputime())
51 }
52
53 d := &deadcodepass{
54 ctxt: ctxt,
55 ifaceMethod: make(map[methodsig]bool),
56 }
57
58
59
60 d.init()
61 d.flood()
62
63 callSym := ctxt.Syms.ROLookup("reflect.Value.Call", sym.SymVerABIInternal)
64 methSym := ctxt.Syms.ROLookup("reflect.Value.Method", sym.SymVerABIInternal)
65 reflectSeen := false
66
67 if ctxt.DynlinkingGo() {
68
69
70 reflectSeen = true
71 }
72
73 for {
74 if !reflectSeen {
75 if d.reflectMethod || (callSym != nil && callSym.Attr.Reachable()) || (methSym != nil && methSym.Attr.Reachable()) {
76
77
78
79 reflectSeen = true
80 }
81 }
82
83
84
85
86
87 var rem []methodref
88 for _, m := range d.markableMethods {
89 if (reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
90 d.markMethod(m)
91 } else {
92 rem = append(rem, m)
93 }
94 }
95 d.markableMethods = rem
96
97 if len(d.markQueue) == 0 {
98
99 break
100 }
101 d.flood()
102 }
103
104
105 for _, m := range d.markableMethods {
106 for _, r := range m.r {
107 d.cleanupReloc(r)
108 }
109 }
110
111 if ctxt.BuildMode != BuildModeShared {
112
113
114 for _, s := range ctxt.Syms.Allsym {
115 if strings.HasPrefix(s.Name, "go.itablink.") {
116 s.Attr.Set(sym.AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable())
117 }
118 }
119 }
120
121 for _, lib := range ctxt.Library {
122 lib.Textp = lib.Textp[:0]
123 }
124
125
126 textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
127 for _, s := range ctxt.Textp {
128 if s.Attr.Reachable() {
129 if s.Lib != nil {
130 s.Lib.Textp = append(s.Lib.Textp, s)
131 }
132 textp = append(textp, s)
133 }
134 }
135 ctxt.Textp = textp
136 }
137
138
139
140
141 type methodref struct {
142 m methodsig
143 src *sym.Symbol
144 r [3]*sym.Reloc
145 }
146
147 func (m methodref) ifn() *sym.Symbol { return m.r[1].Sym }
148
149 func (m methodref) isExported() bool {
150 for _, r := range m.m {
151 return unicode.IsUpper(r)
152 }
153 panic("methodref has no signature")
154 }
155
156
157 type deadcodepass struct {
158 ctxt *Link
159 markQueue []*sym.Symbol
160 ifaceMethod map[methodsig]bool
161 markableMethods []methodref
162 reflectMethod bool
163 }
164
165 func (d *deadcodepass) cleanupReloc(r *sym.Reloc) {
166 if r.Sym.Attr.Reachable() {
167 r.Type = objabi.R_ADDROFF
168 } else {
169 if d.ctxt.Debugvlog > 1 {
170 d.ctxt.Logf("removing method %s\n", r.Sym.Name)
171 }
172 r.Sym = nil
173 r.Siz = 0
174 }
175 }
176
177
178 func (d *deadcodepass) mark(s, parent *sym.Symbol) {
179 if s == nil || s.Attr.Reachable() {
180 return
181 }
182 if s.Attr.ReflectMethod() {
183 d.reflectMethod = true
184 }
185 if *flagDumpDep {
186 p := "_"
187 if parent != nil {
188 p = parent.Name
189 }
190 fmt.Printf("%s -> %s\n", p, s.Name)
191 }
192 s.Attr |= sym.AttrReachable
193 if d.ctxt.Reachparent != nil {
194 d.ctxt.Reachparent[s] = parent
195 }
196 d.markQueue = append(d.markQueue, s)
197 }
198
199
200 func (d *deadcodepass) markMethod(m methodref) {
201 for _, r := range m.r {
202 d.mark(r.Sym, m.src)
203 r.Type = objabi.R_ADDROFF
204 }
205 }
206
207
208
209 func (d *deadcodepass) init() {
210 var names []string
211
212 if d.ctxt.BuildMode == BuildModeShared {
213
214
215 for _, s := range d.ctxt.Syms.Allsym {
216 if s.Type != 0 && s.Type != sym.SDYNIMPORT {
217 d.mark(s, nil)
218 }
219 }
220 } else {
221
222
223
224 if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
225 names = append(names, "main.main", "main..inittask")
226 } else {
227
228 if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
229 if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 {
230 *flagEntrySymbol = "_main"
231 } else {
232 *flagEntrySymbol = "main"
233 }
234 }
235 names = append(names, *flagEntrySymbol)
236 if d.ctxt.BuildMode == BuildModePlugin {
237 names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
238
239
240
241 exports := d.ctxt.Syms.ROLookup("go.plugin.exports", 0)
242 if exports != nil {
243 for i := range exports.R {
244 d.mark(exports.R[i].Sym, nil)
245 }
246 }
247 }
248 }
249 for _, s := range dynexp {
250 d.mark(s, nil)
251 }
252 }
253
254 for _, name := range names {
255
256 d.mark(d.ctxt.Syms.ROLookup(name, 0), nil)
257
258 d.mark(d.ctxt.Syms.ROLookup(name, sym.SymVerABIInternal), nil)
259 }
260 }
261
262
263
264 func (d *deadcodepass) flood() {
265 for len(d.markQueue) > 0 {
266 s := d.markQueue[0]
267 d.markQueue = d.markQueue[1:]
268 if s.Type == sym.STEXT {
269 if d.ctxt.Debugvlog > 1 {
270 d.ctxt.Logf("marktext %s\n", s.Name)
271 }
272 if s.FuncInfo != nil {
273 for _, a := range s.FuncInfo.Autom {
274 d.mark(a.Gotype, s)
275 }
276 }
277
278 }
279
280 if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' {
281 if len(s.P) == 0 {
282
283
284 continue
285 }
286 if decodetypeKind(d.ctxt.Arch, s)&kindMask == kindInterface {
287 for _, sig := range decodeIfaceMethods(d.ctxt.Arch, s) {
288 if d.ctxt.Debugvlog > 1 {
289 d.ctxt.Logf("reached iface method: %s\n", sig)
290 }
291 d.ifaceMethod[sig] = true
292 }
293 }
294 }
295
296 mpos := 0
297 var methods []methodref
298 for i := range s.R {
299 r := &s.R[i]
300 if r.Sym == nil {
301 continue
302 }
303 if r.Type == objabi.R_WEAKADDROFF {
304
305
306
307 continue
308 }
309 if r.Sym.Type == sym.SABIALIAS {
310
311
312 r.Sym = resolveABIAlias(r.Sym)
313 }
314 if r.Type != objabi.R_METHODOFF {
315 d.mark(r.Sym, s)
316 continue
317 }
318
319
320 if mpos == 0 {
321 m := methodref{src: s}
322 m.r[0] = r
323 methods = append(methods, m)
324 } else {
325 methods[len(methods)-1].r[mpos] = r
326 }
327 mpos++
328 if mpos == len(methodref{}.r) {
329 mpos = 0
330 }
331 }
332 if len(methods) > 0 {
333
334
335
336 methodsigs := decodetypeMethods(d.ctxt.Arch, s)
337 if len(methods) != len(methodsigs) {
338 panic(fmt.Sprintf("%q has %d method relocations for %d methods", s.Name, len(methods), len(methodsigs)))
339 }
340 for i, m := range methodsigs {
341 name := string(m)
342 name = name[:strings.Index(name, "(")]
343 if !strings.HasSuffix(methods[i].ifn().Name, name) {
344 panic(fmt.Sprintf("%q relocation for %q does not match method %q", s.Name, methods[i].ifn().Name, name))
345 }
346 methods[i].m = m
347 }
348 d.markableMethods = append(d.markableMethods, methods...)
349 }
350
351 if s.FuncInfo != nil {
352 for i := range s.FuncInfo.Funcdata {
353 d.mark(s.FuncInfo.Funcdata[i], s)
354 }
355 }
356 d.mark(s.Gotype, s)
357 d.mark(s.Sub, s)
358 d.mark(s.Outer, s)
359 }
360 }
361
View as plain text