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