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 )
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) rodataKind() (suffix string, typ objabi.SymKind) {
141 return "", objabi.SRODATA
142 }
143
144 func (ctxt *Link) Float32Sym(f float32) *LSym {
145 suffix, typ := ctxt.rodataKind()
146 i := math.Float32bits(f)
147 name := fmt.Sprintf("$f32.%08x%s", i, suffix)
148 return ctxt.LookupInit(name, func(s *LSym) {
149 s.Size = 4
150 s.WriteFloat32(ctxt, 0, f)
151 s.Type = typ
152 s.Set(AttrLocal, true)
153 s.Set(AttrContentAddressable, true)
154 ctxt.constSyms = append(ctxt.constSyms, s)
155 })
156 }
157
158 func (ctxt *Link) Float64Sym(f float64) *LSym {
159 suffix, typ := ctxt.rodataKind()
160 i := math.Float64bits(f)
161 name := fmt.Sprintf("$f64.%016x%s", i, suffix)
162 return ctxt.LookupInit(name, func(s *LSym) {
163 s.Size = 8
164 s.WriteFloat64(ctxt, 0, f)
165 s.Type = typ
166 s.Set(AttrLocal, true)
167 s.Set(AttrContentAddressable, true)
168 ctxt.constSyms = append(ctxt.constSyms, s)
169 })
170 }
171
172 func (ctxt *Link) Int32Sym(i int64) *LSym {
173 suffix, typ := ctxt.rodataKind()
174 name := fmt.Sprintf("$i32.%08x%s", uint64(i), suffix)
175 return ctxt.LookupInit(name, func(s *LSym) {
176 s.Size = 4
177 s.WriteInt(ctxt, 0, 4, i)
178 s.Type = typ
179 s.Set(AttrLocal, true)
180 s.Set(AttrContentAddressable, true)
181 ctxt.constSyms = append(ctxt.constSyms, s)
182 })
183 }
184
185 func (ctxt *Link) Int64Sym(i int64) *LSym {
186 suffix, typ := ctxt.rodataKind()
187 name := fmt.Sprintf("$i64.%016x%s", uint64(i), suffix)
188 return ctxt.LookupInit(name, func(s *LSym) {
189 s.Size = 8
190 s.WriteInt(ctxt, 0, 8, i)
191 s.Type = typ
192 s.Set(AttrLocal, true)
193 s.Set(AttrContentAddressable, true)
194 ctxt.constSyms = append(ctxt.constSyms, s)
195 })
196 }
197
198 func (ctxt *Link) Int128Sym(hi, lo int64) *LSym {
199 suffix, typ := ctxt.rodataKind()
200 name := fmt.Sprintf("$i128.%016x%016x%s", uint64(hi), uint64(lo), suffix)
201 return ctxt.LookupInit(name, func(s *LSym) {
202 s.Size = 16
203 if ctxt.Arch.ByteOrder == binary.LittleEndian {
204 s.WriteInt(ctxt, 0, 8, lo)
205 s.WriteInt(ctxt, 8, 8, hi)
206 } else {
207 s.WriteInt(ctxt, 0, 8, hi)
208 s.WriteInt(ctxt, 8, 8, lo)
209 }
210 s.Type = typ
211 s.Set(AttrLocal, true)
212 s.Set(AttrContentAddressable, true)
213 ctxt.constSyms = append(ctxt.constSyms, s)
214 })
215 }
216
217
218 func (ctxt *Link) GCLocalsSym(data []byte) *LSym {
219 sum := hash.Sum16(data)
220 str := base64.StdEncoding.EncodeToString(sum[:16])
221 return ctxt.LookupInit(fmt.Sprintf("gclocals·%s", str), func(lsym *LSym) {
222 lsym.P = data
223 lsym.Set(AttrContentAddressable, true)
224 })
225 }
226
227
228
229
230 func (ctxt *Link) NumberSyms() {
231 if ctxt.Pkgpath == "" {
232 panic("NumberSyms called without package path")
233 }
234
235 if ctxt.Headtype == objabi.Haix {
236
237
238
239
240
241
242
243
244 sort.SliceStable(ctxt.Data, func(i, j int) bool {
245 return ctxt.Data[i].Name < ctxt.Data[j].Name
246 })
247 }
248
249
250
251 sort.Slice(ctxt.constSyms, func(i, j int) bool {
252 return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name
253 })
254 ctxt.Data = append(ctxt.Data, ctxt.constSyms...)
255 ctxt.constSyms = nil
256
257
258 sort.Slice(ctxt.SEHSyms, func(i, j int) bool {
259 return ctxt.SEHSyms[i].Name < ctxt.SEHSyms[j].Name
260 })
261 ctxt.Data = append(ctxt.Data, ctxt.SEHSyms...)
262 ctxt.SEHSyms = nil
263
264 ctxt.pkgIdx = make(map[string]int32)
265 ctxt.defs = []*LSym{}
266 ctxt.hashed64defs = []*LSym{}
267 ctxt.hasheddefs = []*LSym{}
268 ctxt.nonpkgdefs = []*LSym{}
269
270 var idx, hashedidx, hashed64idx, nonpkgidx int32
271 ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) {
272 if s.ContentAddressable() {
273 if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 {
274
275
276
277 s.PkgIdx = goobj.PkgIdxHashed64
278 s.SymIdx = hashed64idx
279 if hashed64idx != int32(len(ctxt.hashed64defs)) {
280 panic("bad index")
281 }
282 ctxt.hashed64defs = append(ctxt.hashed64defs, s)
283 hashed64idx++
284 } else {
285 s.PkgIdx = goobj.PkgIdxHashed
286 s.SymIdx = hashedidx
287 if hashedidx != int32(len(ctxt.hasheddefs)) {
288 panic("bad index")
289 }
290 ctxt.hasheddefs = append(ctxt.hasheddefs, s)
291 hashedidx++
292 }
293 } else if isNonPkgSym(ctxt, s) {
294 s.PkgIdx = goobj.PkgIdxNone
295 s.SymIdx = nonpkgidx
296 if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
297 panic("bad index")
298 }
299 ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
300 nonpkgidx++
301 } else {
302 s.PkgIdx = goobj.PkgIdxSelf
303 s.SymIdx = idx
304 if idx != int32(len(ctxt.defs)) {
305 panic("bad index")
306 }
307 ctxt.defs = append(ctxt.defs, s)
308 idx++
309 }
310 s.Set(AttrIndexed, true)
311 })
312
313 ipkg := int32(1)
314 nonpkgdef := nonpkgidx
315 ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
316 if rs.PkgIdx != goobj.PkgIdxInvalid {
317 return
318 }
319 if !ctxt.Flag_linkshared {
320
321
322
323 if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
324 rs.PkgIdx = goobj.PkgIdxBuiltin
325 rs.SymIdx = int32(i)
326 rs.Set(AttrIndexed, true)
327 return
328 }
329 }
330 pkg := rs.Pkg
331 if rs.ContentAddressable() {
332
333 panic("hashed refs unsupported for now")
334 }
335 if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
336 rs.PkgIdx = goobj.PkgIdxNone
337 rs.SymIdx = nonpkgidx
338 rs.Set(AttrIndexed, true)
339 if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
340 panic("bad index")
341 }
342 ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
343 nonpkgidx++
344 return
345 }
346 if k, ok := ctxt.pkgIdx[pkg]; ok {
347 rs.PkgIdx = k
348 return
349 }
350 rs.PkgIdx = ipkg
351 ctxt.pkgIdx[pkg] = ipkg
352 ipkg++
353 })
354 }
355
356
357
358 func isNonPkgSym(ctxt *Link, s *LSym) bool {
359 if ctxt.IsAsm && !s.Static() {
360
361
362 return true
363 }
364 if ctxt.Flag_linkshared {
365
366
367 return true
368 }
369 if s.Pkg == "_" {
370
371
372 return true
373 }
374 if s.DuplicateOK() {
375
376 return true
377 }
378 return false
379 }
380
381
382
383
384 const StaticNamePrefix = ".stmp_"
385
386 type traverseFlag uint32
387
388 const (
389 traverseDefs traverseFlag = 1 << iota
390 traverseRefs
391 traverseAux
392 traversePcdata
393
394 traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata
395 )
396
397
398 func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
399 fnNoNil := func(s *LSym) {
400 if s != nil {
401 fn(s)
402 }
403 }
404 lists := [][]*LSym{ctxt.Text, ctxt.Data}
405 files := ctxt.PosTable.FileTable()
406 for _, list := range lists {
407 for _, s := range list {
408 if flag&traverseDefs != 0 {
409 fn(s)
410 }
411 if flag&traverseRefs != 0 {
412 for _, r := range s.R {
413 fnNoNil(r.Sym)
414 }
415 }
416 if flag&traverseAux != 0 {
417 fnNoNil(s.Gotype)
418 if s.Type.IsText() {
419 f := func(parent *LSym, aux *LSym) {
420 fn(aux)
421 }
422 ctxt.traverseFuncAux(flag, s, f, files)
423 } else if v := s.VarInfo(); v != nil {
424 fnNoNil(v.dwarfInfoSym)
425 }
426 }
427 if flag&traversePcdata != 0 && s.Type.IsText() {
428 fi := s.Func().Pcln
429 fnNoNil(fi.Pcsp)
430 fnNoNil(fi.Pcfile)
431 fnNoNil(fi.Pcline)
432 fnNoNil(fi.Pcinline)
433 for _, d := range fi.Pcdata {
434 fnNoNil(d)
435 }
436 }
437 }
438 }
439 }
440
441 func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym), files []string) {
442 fninfo := fsym.Func()
443 pc := &fninfo.Pcln
444 if flag&traverseAux == 0 {
445
446
447 panic("should not be here")
448 }
449 for _, d := range pc.Funcdata {
450 if d != nil {
451 fn(fsym, d)
452 }
453 }
454 usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
455 for f := range pc.UsedFiles {
456 usedFiles = append(usedFiles, f)
457 }
458 sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
459 for _, f := range usedFiles {
460 if filesym := ctxt.Lookup(files[f]); filesym != nil {
461 fn(fsym, filesym)
462 }
463 }
464 for _, call := range pc.InlTree.nodes {
465 if call.Func != nil {
466 fn(fsym, call.Func)
467 }
468 }
469
470 auxsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym, fninfo.sehUnwindInfoSym}
471 if wi := fninfo.WasmImport; wi != nil {
472 auxsyms = append(auxsyms, wi.AuxSym)
473 }
474 if we := fninfo.WasmExport; we != nil {
475 auxsyms = append(auxsyms, we.AuxSym)
476 }
477 for _, s := range auxsyms {
478 if s == nil || s.Size == 0 {
479 continue
480 }
481 fn(fsym, s)
482 if flag&traverseRefs != 0 {
483 for _, r := range s.R {
484 if r.Sym != nil {
485 fn(s, r.Sym)
486 }
487 }
488 }
489 }
490 }
491
492
493 func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
494 lists := [][]*LSym{ctxt.Text, ctxt.Data}
495 files := ctxt.PosTable.FileTable()
496 for _, list := range lists {
497 for _, s := range list {
498 if s.Gotype != nil {
499 if flag&traverseDefs != 0 {
500 fn(s, s.Gotype)
501 }
502 }
503 if s.Type.IsText() {
504 ctxt.traverseFuncAux(flag, s, fn, files)
505 } else if v := s.VarInfo(); v != nil && v.dwarfInfoSym != nil {
506 fn(s, v.dwarfInfoSym)
507 }
508 }
509 }
510 }
511
View as plain text