1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package obj
33
34 import (
35 "cmd/internal/goobj"
36 "cmd/internal/objabi"
37 "crypto/md5"
38 "fmt"
39 "internal/buildcfg"
40 "log"
41 "math"
42 "sort"
43 )
44
45 func Linknew(arch *LinkArch) *Link {
46 ctxt := new(Link)
47 ctxt.hash = make(map[string]*LSym)
48 ctxt.funchash = make(map[string]*LSym)
49 ctxt.statichash = make(map[string]*LSym)
50 ctxt.Arch = arch
51 ctxt.Pathname = objabi.WorkingDir()
52
53 if err := ctxt.Headtype.Set(buildcfg.GOOS); err != nil {
54 log.Fatalf("unknown goos %s", buildcfg.GOOS)
55 }
56
57 ctxt.Flag_optimize = true
58 return ctxt
59 }
60
61
62
63 func (ctxt *Link) LookupDerived(s *LSym, name string) *LSym {
64 if s.Static() {
65 return ctxt.LookupStatic(name)
66 }
67 return ctxt.Lookup(name)
68 }
69
70
71
72 func (ctxt *Link) LookupStatic(name string) *LSym {
73 s := ctxt.statichash[name]
74 if s == nil {
75 s = &LSym{Name: name, Attribute: AttrStatic}
76 ctxt.statichash[name] = s
77 }
78 return s
79 }
80
81
82
83 func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
84 return ctxt.LookupABIInit(name, abi, nil)
85 }
86
87
88
89
90 func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
91 var hash map[string]*LSym
92 switch abi {
93 case ABI0:
94 hash = ctxt.hash
95 case ABIInternal:
96 hash = ctxt.funchash
97 default:
98 panic("unknown ABI")
99 }
100
101 ctxt.hashmu.Lock()
102 s := hash[name]
103 if s == nil {
104 s = &LSym{Name: name}
105 s.SetABI(abi)
106 hash[name] = s
107 if init != nil {
108 init(s)
109 }
110 }
111 ctxt.hashmu.Unlock()
112 return s
113 }
114
115
116
117 func (ctxt *Link) Lookup(name string) *LSym {
118 return ctxt.LookupInit(name, nil)
119 }
120
121
122
123
124 func (ctxt *Link) LookupInit(name string, init func(s *LSym)) *LSym {
125 ctxt.hashmu.Lock()
126 s := ctxt.hash[name]
127 if s == nil {
128 s = &LSym{Name: name}
129 ctxt.hash[name] = s
130 if init != nil {
131 init(s)
132 }
133 }
134 ctxt.hashmu.Unlock()
135 return s
136 }
137
138 func (ctxt *Link) Float32Sym(f float32) *LSym {
139 i := math.Float32bits(f)
140 name := fmt.Sprintf("$f32.%08x", i)
141 return ctxt.LookupInit(name, func(s *LSym) {
142 s.Size = 4
143 s.WriteFloat32(ctxt, 0, f)
144 s.Type = objabi.SRODATA
145 s.Set(AttrLocal, true)
146 s.Set(AttrContentAddressable, true)
147 ctxt.constSyms = append(ctxt.constSyms, s)
148 })
149 }
150
151 func (ctxt *Link) Float64Sym(f float64) *LSym {
152 i := math.Float64bits(f)
153 name := fmt.Sprintf("$f64.%016x", i)
154 return ctxt.LookupInit(name, func(s *LSym) {
155 s.Size = 8
156 s.WriteFloat64(ctxt, 0, f)
157 s.Type = objabi.SRODATA
158 s.Set(AttrLocal, true)
159 s.Set(AttrContentAddressable, true)
160 ctxt.constSyms = append(ctxt.constSyms, s)
161 })
162 }
163
164 func (ctxt *Link) Int64Sym(i int64) *LSym {
165 name := fmt.Sprintf("$i64.%016x", uint64(i))
166 return ctxt.LookupInit(name, func(s *LSym) {
167 s.Size = 8
168 s.WriteInt(ctxt, 0, 8, i)
169 s.Type = objabi.SRODATA
170 s.Set(AttrLocal, true)
171 s.Set(AttrContentAddressable, true)
172 ctxt.constSyms = append(ctxt.constSyms, s)
173 })
174 }
175
176
177 func (ctxt *Link) GCLocalsSym(data []byte) *LSym {
178 return ctxt.LookupInit(fmt.Sprintf("gclocals·%x", md5.Sum(data)), func(lsym *LSym) {
179 lsym.P = data
180 lsym.Set(AttrContentAddressable, true)
181 })
182 }
183
184
185
186
187 func (ctxt *Link) NumberSyms() {
188 if ctxt.Headtype == objabi.Haix {
189
190
191
192
193 sort.Slice(ctxt.Data, func(i, j int) bool {
194 return ctxt.Data[i].Name < ctxt.Data[j].Name
195 })
196 }
197
198
199
200 sort.Slice(ctxt.constSyms, func(i, j int) bool {
201 return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name
202 })
203 ctxt.Data = append(ctxt.Data, ctxt.constSyms...)
204 ctxt.constSyms = nil
205
206 ctxt.pkgIdx = make(map[string]int32)
207 ctxt.defs = []*LSym{}
208 ctxt.hashed64defs = []*LSym{}
209 ctxt.hasheddefs = []*LSym{}
210 ctxt.nonpkgdefs = []*LSym{}
211
212 var idx, hashedidx, hashed64idx, nonpkgidx int32
213 ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) {
214
215
216 if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
217 if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 {
218
219
220
221 s.PkgIdx = goobj.PkgIdxHashed64
222 s.SymIdx = hashed64idx
223 if hashed64idx != int32(len(ctxt.hashed64defs)) {
224 panic("bad index")
225 }
226 ctxt.hashed64defs = append(ctxt.hashed64defs, s)
227 hashed64idx++
228 } else {
229 s.PkgIdx = goobj.PkgIdxHashed
230 s.SymIdx = hashedidx
231 if hashedidx != int32(len(ctxt.hasheddefs)) {
232 panic("bad index")
233 }
234 ctxt.hasheddefs = append(ctxt.hasheddefs, s)
235 hashedidx++
236 }
237 } else if isNonPkgSym(ctxt, s) {
238 s.PkgIdx = goobj.PkgIdxNone
239 s.SymIdx = nonpkgidx
240 if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
241 panic("bad index")
242 }
243 ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
244 nonpkgidx++
245 } else {
246 s.PkgIdx = goobj.PkgIdxSelf
247 s.SymIdx = idx
248 if idx != int32(len(ctxt.defs)) {
249 panic("bad index")
250 }
251 ctxt.defs = append(ctxt.defs, s)
252 idx++
253 }
254 s.Set(AttrIndexed, true)
255 })
256
257 ipkg := int32(1)
258 nonpkgdef := nonpkgidx
259 ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
260 if rs.PkgIdx != goobj.PkgIdxInvalid {
261 return
262 }
263 if !ctxt.Flag_linkshared {
264
265
266
267 if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
268 rs.PkgIdx = goobj.PkgIdxBuiltin
269 rs.SymIdx = int32(i)
270 rs.Set(AttrIndexed, true)
271 return
272 }
273 }
274 pkg := rs.Pkg
275 if rs.ContentAddressable() {
276
277 panic("hashed refs unsupported for now")
278 }
279 if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
280 rs.PkgIdx = goobj.PkgIdxNone
281 rs.SymIdx = nonpkgidx
282 rs.Set(AttrIndexed, true)
283 if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
284 panic("bad index")
285 }
286 ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
287 nonpkgidx++
288 return
289 }
290 if k, ok := ctxt.pkgIdx[pkg]; ok {
291 rs.PkgIdx = k
292 return
293 }
294 rs.PkgIdx = ipkg
295 ctxt.pkgIdx[pkg] = ipkg
296 ipkg++
297 })
298 }
299
300
301
302 func isNonPkgSym(ctxt *Link, s *LSym) bool {
303 if ctxt.IsAsm && !s.Static() {
304
305
306 return true
307 }
308 if ctxt.Flag_linkshared {
309
310
311 return true
312 }
313 if s.Pkg == "_" {
314
315
316 return true
317 }
318 if s.DuplicateOK() {
319
320 return true
321 }
322 return false
323 }
324
325
326
327
328 const StaticNamePref = ".stmp_"
329
330 type traverseFlag uint32
331
332 const (
333 traverseDefs traverseFlag = 1 << iota
334 traverseRefs
335 traverseAux
336 traversePcdata
337
338 traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata
339 )
340
341
342 func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
343 fnNoNil := func(s *LSym) {
344 if s != nil {
345 fn(s)
346 }
347 }
348 lists := [][]*LSym{ctxt.Text, ctxt.Data}
349 for _, list := range lists {
350 for _, s := range list {
351 if flag&traverseDefs != 0 {
352 fn(s)
353 }
354 if flag&traverseRefs != 0 {
355 for _, r := range s.R {
356 fnNoNil(r.Sym)
357 }
358 }
359 if flag&traverseAux != 0 {
360 fnNoNil(s.Gotype)
361 if s.Type == objabi.STEXT {
362 f := func(parent *LSym, aux *LSym) {
363 fn(aux)
364 }
365 ctxt.traverseFuncAux(flag, s, f)
366 }
367 }
368 if flag&traversePcdata != 0 && s.Type == objabi.STEXT {
369 fi := s.Func().Pcln
370 fnNoNil(fi.Pcsp)
371 fnNoNil(fi.Pcfile)
372 fnNoNil(fi.Pcline)
373 fnNoNil(fi.Pcinline)
374 for _, d := range fi.Pcdata {
375 fnNoNil(d)
376 }
377 }
378 }
379 }
380 }
381
382 func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym)) {
383 fninfo := fsym.Func()
384 pc := &fninfo.Pcln
385 if flag&traverseAux == 0 {
386
387
388 panic("should not be here")
389 }
390 for _, d := range pc.Funcdata {
391 if d != nil {
392 fn(fsym, d)
393 }
394 }
395 files := ctxt.PosTable.FileTable()
396 usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
397 for f := range pc.UsedFiles {
398 usedFiles = append(usedFiles, f)
399 }
400 sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
401 for _, f := range usedFiles {
402 if filesym := ctxt.Lookup(files[f]); filesym != nil {
403 fn(fsym, filesym)
404 }
405 }
406 for _, call := range pc.InlTree.nodes {
407 if call.Func != nil {
408 fn(fsym, call.Func)
409 }
410 f, _ := linkgetlineFromPos(ctxt, call.Pos)
411 if filesym := ctxt.Lookup(f); filesym != nil {
412 fn(fsym, filesym)
413 }
414 }
415
416 dwsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym}
417 for _, dws := range dwsyms {
418 if dws == nil || dws.Size == 0 {
419 continue
420 }
421 fn(fsym, dws)
422 if flag&traverseRefs != 0 {
423 for _, r := range dws.R {
424 if r.Sym != nil {
425 fn(dws, r.Sym)
426 }
427 }
428 }
429 }
430 }
431
432
433 func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
434 lists := [][]*LSym{ctxt.Text, ctxt.Data}
435 for _, list := range lists {
436 for _, s := range list {
437 if s.Gotype != nil {
438 if flag&traverseDefs != 0 {
439 fn(s, s.Gotype)
440 }
441 }
442 if s.Type != objabi.STEXT {
443 continue
444 }
445 ctxt.traverseFuncAux(flag, s, fn)
446 }
447 }
448 }
449
View as plain text