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