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 "fmt"
38 "internal/buildcfg"
39 "log"
40 "math"
41 "sort"
42 "strings"
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
178
179 func (ctxt *Link) NumberSyms() {
180 if ctxt.Headtype == objabi.Haix {
181
182
183
184
185 sort.Slice(ctxt.Data, func(i, j int) bool {
186 return ctxt.Data[i].Name < ctxt.Data[j].Name
187 })
188 }
189
190
191
192 sort.Slice(ctxt.constSyms, func(i, j int) bool {
193 return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name
194 })
195 ctxt.Data = append(ctxt.Data, ctxt.constSyms...)
196 ctxt.constSyms = nil
197
198 ctxt.pkgIdx = make(map[string]int32)
199 ctxt.defs = []*LSym{}
200 ctxt.hashed64defs = []*LSym{}
201 ctxt.hasheddefs = []*LSym{}
202 ctxt.nonpkgdefs = []*LSym{}
203
204 var idx, hashedidx, hashed64idx, nonpkgidx int32
205 ctxt.traverseSyms(traverseDefs, func(s *LSym) {
206
207
208 if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
209 if s.Size <= 8 && len(s.R) == 0 && !strings.HasPrefix(s.Name, "type.") {
210
211
212 s.PkgIdx = goobj.PkgIdxHashed64
213 s.SymIdx = hashed64idx
214 if hashed64idx != int32(len(ctxt.hashed64defs)) {
215 panic("bad index")
216 }
217 ctxt.hashed64defs = append(ctxt.hashed64defs, s)
218 hashed64idx++
219 } else {
220 s.PkgIdx = goobj.PkgIdxHashed
221 s.SymIdx = hashedidx
222 if hashedidx != int32(len(ctxt.hasheddefs)) {
223 panic("bad index")
224 }
225 ctxt.hasheddefs = append(ctxt.hasheddefs, s)
226 hashedidx++
227 }
228 } else if isNonPkgSym(ctxt, s) {
229 s.PkgIdx = goobj.PkgIdxNone
230 s.SymIdx = nonpkgidx
231 if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
232 panic("bad index")
233 }
234 ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
235 nonpkgidx++
236 } else {
237 s.PkgIdx = goobj.PkgIdxSelf
238 s.SymIdx = idx
239 if idx != int32(len(ctxt.defs)) {
240 panic("bad index")
241 }
242 ctxt.defs = append(ctxt.defs, s)
243 idx++
244 }
245 s.Set(AttrIndexed, true)
246 })
247
248 ipkg := int32(1)
249 nonpkgdef := nonpkgidx
250 ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
251 if rs.PkgIdx != goobj.PkgIdxInvalid {
252 return
253 }
254 if !ctxt.Flag_linkshared {
255
256
257
258 if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
259 rs.PkgIdx = goobj.PkgIdxBuiltin
260 rs.SymIdx = int32(i)
261 rs.Set(AttrIndexed, true)
262 return
263 }
264 }
265 pkg := rs.Pkg
266 if rs.ContentAddressable() {
267
268 panic("hashed refs unsupported for now")
269 }
270 if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
271 rs.PkgIdx = goobj.PkgIdxNone
272 rs.SymIdx = nonpkgidx
273 rs.Set(AttrIndexed, true)
274 if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
275 panic("bad index")
276 }
277 ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
278 nonpkgidx++
279 return
280 }
281 if k, ok := ctxt.pkgIdx[pkg]; ok {
282 rs.PkgIdx = k
283 return
284 }
285 rs.PkgIdx = ipkg
286 ctxt.pkgIdx[pkg] = ipkg
287 ipkg++
288 })
289 }
290
291
292
293 func isNonPkgSym(ctxt *Link, s *LSym) bool {
294 if ctxt.IsAsm && !s.Static() {
295
296
297 return true
298 }
299 if ctxt.Flag_linkshared {
300
301
302 return true
303 }
304 if s.Pkg == "_" {
305
306
307 return true
308 }
309 if s.DuplicateOK() {
310
311 return true
312 }
313 return false
314 }
315
316
317
318
319 const StaticNamePref = ".stmp_"
320
321 type traverseFlag uint32
322
323 const (
324 traverseDefs traverseFlag = 1 << iota
325 traverseRefs
326 traverseAux
327
328 traverseAll = traverseDefs | traverseRefs | traverseAux
329 )
330
331
332 func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
333 lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
334 for _, list := range lists {
335 for _, s := range list {
336 if flag&traverseDefs != 0 {
337 fn(s)
338 }
339 if flag&traverseRefs != 0 {
340 for _, r := range s.R {
341 if r.Sym != nil {
342 fn(r.Sym)
343 }
344 }
345 }
346 if flag&traverseAux != 0 {
347 if s.Gotype != nil {
348 fn(s.Gotype)
349 }
350 if s.Type == objabi.STEXT {
351 f := func(parent *LSym, aux *LSym) {
352 fn(aux)
353 }
354 ctxt.traverseFuncAux(flag, s, f)
355 }
356 }
357 }
358 }
359 }
360
361 func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym)) {
362 fninfo := fsym.Func()
363 pc := &fninfo.Pcln
364 if flag&traverseAux == 0 {
365
366
367 panic("should not be here")
368 }
369 for _, d := range pc.Funcdata {
370 if d != nil {
371 fn(fsym, d)
372 }
373 }
374 files := ctxt.PosTable.FileTable()
375 usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
376 for f := range pc.UsedFiles {
377 usedFiles = append(usedFiles, f)
378 }
379 sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
380 for _, f := range usedFiles {
381 if filesym := ctxt.Lookup(files[f]); filesym != nil {
382 fn(fsym, filesym)
383 }
384 }
385 for _, call := range pc.InlTree.nodes {
386 if call.Func != nil {
387 fn(fsym, call.Func)
388 }
389 f, _ := linkgetlineFromPos(ctxt, call.Pos)
390 if filesym := ctxt.Lookup(f); filesym != nil {
391 fn(fsym, filesym)
392 }
393 }
394
395 dwsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym}
396 for _, dws := range dwsyms {
397 if dws == nil || dws.Size == 0 {
398 continue
399 }
400 fn(fsym, dws)
401 if flag&traverseRefs != 0 {
402 for _, r := range dws.R {
403 if r.Sym != nil {
404 fn(dws, r.Sym)
405 }
406 }
407 }
408 }
409 }
410
411
412 func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
413 lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
414 for _, list := range lists {
415 for _, s := range list {
416 if s.Gotype != nil {
417 if flag&traverseDefs != 0 {
418 fn(s, s.Gotype)
419 }
420 }
421 if s.Type != objabi.STEXT {
422 continue
423 }
424 ctxt.traverseFuncAux(flag, s, fn)
425 }
426 }
427 }
428
View as plain text