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 ctxt.pkgIdx = make(map[string]int32)
249 ctxt.defs = []*LSym{}
250 ctxt.hashed64defs = []*LSym{}
251 ctxt.hasheddefs = []*LSym{}
252 ctxt.nonpkgdefs = []*LSym{}
253
254 var idx, hashedidx, hashed64idx, nonpkgidx int32
255 ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) {
256 if s.ContentAddressable() {
257 if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 {
258
259
260
261 s.PkgIdx = goobj.PkgIdxHashed64
262 s.SymIdx = hashed64idx
263 if hashed64idx != int32(len(ctxt.hashed64defs)) {
264 panic("bad index")
265 }
266 ctxt.hashed64defs = append(ctxt.hashed64defs, s)
267 hashed64idx++
268 } else {
269 s.PkgIdx = goobj.PkgIdxHashed
270 s.SymIdx = hashedidx
271 if hashedidx != int32(len(ctxt.hasheddefs)) {
272 panic("bad index")
273 }
274 ctxt.hasheddefs = append(ctxt.hasheddefs, s)
275 hashedidx++
276 }
277 } else if isNonPkgSym(ctxt, s) {
278 s.PkgIdx = goobj.PkgIdxNone
279 s.SymIdx = nonpkgidx
280 if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
281 panic("bad index")
282 }
283 ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
284 nonpkgidx++
285 } else {
286 s.PkgIdx = goobj.PkgIdxSelf
287 s.SymIdx = idx
288 if idx != int32(len(ctxt.defs)) {
289 panic("bad index")
290 }
291 ctxt.defs = append(ctxt.defs, s)
292 idx++
293 }
294 s.Set(AttrIndexed, true)
295 })
296
297 ipkg := int32(1)
298 nonpkgdef := nonpkgidx
299 ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
300 if rs.PkgIdx != goobj.PkgIdxInvalid {
301 return
302 }
303 if !ctxt.Flag_linkshared {
304
305
306
307 if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
308 rs.PkgIdx = goobj.PkgIdxBuiltin
309 rs.SymIdx = int32(i)
310 rs.Set(AttrIndexed, true)
311 return
312 }
313 }
314 pkg := rs.Pkg
315 if rs.ContentAddressable() {
316
317 panic("hashed refs unsupported for now")
318 }
319 if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
320 rs.PkgIdx = goobj.PkgIdxNone
321 rs.SymIdx = nonpkgidx
322 rs.Set(AttrIndexed, true)
323 if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
324 panic("bad index")
325 }
326 ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
327 nonpkgidx++
328 return
329 }
330 if k, ok := ctxt.pkgIdx[pkg]; ok {
331 rs.PkgIdx = k
332 return
333 }
334 rs.PkgIdx = ipkg
335 ctxt.pkgIdx[pkg] = ipkg
336 ipkg++
337 })
338 }
339
340
341
342 func isNonPkgSym(ctxt *Link, s *LSym) bool {
343 if ctxt.IsAsm && !s.Static() {
344
345
346 return true
347 }
348 if ctxt.Flag_linkshared {
349
350
351 return true
352 }
353 if s.Pkg == "_" {
354
355
356 return true
357 }
358 if s.DuplicateOK() {
359
360 return true
361 }
362 return false
363 }
364
365
366
367
368 const StaticNamePref = ".stmp_"
369
370 type traverseFlag uint32
371
372 const (
373 traverseDefs traverseFlag = 1 << iota
374 traverseRefs
375 traverseAux
376 traversePcdata
377
378 traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata
379 )
380
381
382 func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
383 fnNoNil := func(s *LSym) {
384 if s != nil {
385 fn(s)
386 }
387 }
388 lists := [][]*LSym{ctxt.Text, ctxt.Data}
389 files := ctxt.PosTable.FileTable()
390 for _, list := range lists {
391 for _, s := range list {
392 if flag&traverseDefs != 0 {
393 fn(s)
394 }
395 if flag&traverseRefs != 0 {
396 for _, r := range s.R {
397 fnNoNil(r.Sym)
398 }
399 }
400 if flag&traverseAux != 0 {
401 fnNoNil(s.Gotype)
402 if s.Type == objabi.STEXT {
403 f := func(parent *LSym, aux *LSym) {
404 fn(aux)
405 }
406 ctxt.traverseFuncAux(flag, s, f, files)
407 } else if v := s.VarInfo(); v != nil {
408 fnNoNil(v.dwarfInfoSym)
409 }
410 }
411 if flag&traversePcdata != 0 && s.Type == objabi.STEXT {
412 fi := s.Func().Pcln
413 fnNoNil(fi.Pcsp)
414 fnNoNil(fi.Pcfile)
415 fnNoNil(fi.Pcline)
416 fnNoNil(fi.Pcinline)
417 for _, d := range fi.Pcdata {
418 fnNoNil(d)
419 }
420 }
421 }
422 }
423 }
424
425 func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym), files []string) {
426 fninfo := fsym.Func()
427 pc := &fninfo.Pcln
428 if flag&traverseAux == 0 {
429
430
431 panic("should not be here")
432 }
433 for _, d := range pc.Funcdata {
434 if d != nil {
435 fn(fsym, d)
436 }
437 }
438 usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
439 for f := range pc.UsedFiles {
440 usedFiles = append(usedFiles, f)
441 }
442 sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
443 for _, f := range usedFiles {
444 if filesym := ctxt.Lookup(files[f]); filesym != nil {
445 fn(fsym, filesym)
446 }
447 }
448 for _, call := range pc.InlTree.nodes {
449 if call.Func != nil {
450 fn(fsym, call.Func)
451 }
452 }
453
454 auxsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym, fninfo.WasmImportSym, fninfo.sehUnwindInfoSym}
455 for _, s := range auxsyms {
456 if s == nil || s.Size == 0 {
457 continue
458 }
459 fn(fsym, s)
460 if flag&traverseRefs != 0 {
461 for _, r := range s.R {
462 if r.Sym != nil {
463 fn(s, r.Sym)
464 }
465 }
466 }
467 }
468 }
469
470
471 func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
472 lists := [][]*LSym{ctxt.Text, ctxt.Data}
473 files := ctxt.PosTable.FileTable()
474 for _, list := range lists {
475 for _, s := range list {
476 if s.Gotype != nil {
477 if flag&traverseDefs != 0 {
478 fn(s, s.Gotype)
479 }
480 }
481 if s.Type == objabi.STEXT {
482 ctxt.traverseFuncAux(flag, s, fn, files)
483 } else if v := s.VarInfo(); v != nil && v.dwarfInfoSym != nil {
484 fn(s, v.dwarfInfoSym)
485 }
486 }
487 }
488 }
489
View as plain text