]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/sym.go
internal/buildcfg: move build configuration out of cmd/internal/objabi
[gostls13.git] / src / cmd / internal / obj / sym.go
1 // Derived from Inferno utils/6l/obj.c and utils/6l/span.c
2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
3 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
4 //
5 //      Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
6 //      Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
7 //      Portions Copyright © 1997-1999 Vita Nuova Limited
8 //      Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
9 //      Portions Copyright © 2004,2006 Bruce Ellis
10 //      Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
11 //      Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
12 //      Portions Copyright © 2009 The Go Authors. All rights reserved.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to deal
16 // in the Software without restriction, including without limitation the rights
17 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 // copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included in
22 // all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
27 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 // THE SOFTWARE.
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 // LookupDerived looks up or creates the symbol with name derived from symbol s.
62 // The resulting symbol will be static iff s is.
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 // LookupStatic looks up the static symbol with name name.
71 // If it does not exist, it creates it.
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 // LookupABI looks up a symbol with the given ABI.
82 // If it does not exist, it creates it.
83 func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
84         return ctxt.LookupABIInit(name, abi, nil)
85 }
86
87 // LookupABI looks up a symbol with the given ABI.
88 // If it does not exist, it creates it and
89 // passes it to init for one-time initialization.
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 // Lookup looks up the symbol with name name.
116 // If it does not exist, it creates it.
117 func (ctxt *Link) Lookup(name string) *LSym {
118         return ctxt.LookupInit(name, nil)
119 }
120
121 // LookupInit looks up the symbol with name name.
122 // If it does not exist, it creates it and
123 // passes it to init for one-time initialization.
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 // Assign index to symbols.
177 // asm is set to true if this is called by the assembler (i.e. not the compiler),
178 // in which case all the symbols are non-package (for now).
179 func (ctxt *Link) NumberSyms() {
180         if ctxt.Headtype == objabi.Haix {
181                 // Data must be sorted to keep a constant order in TOC symbols.
182                 // As they are created during Progedit, two symbols can be switched between
183                 // two different compilations. Therefore, BuildID will be different.
184                 // TODO: find a better place and optimize to only sort TOC symbols
185                 sort.Slice(ctxt.Data, func(i, j int) bool {
186                         return ctxt.Data[i].Name < ctxt.Data[j].Name
187                 })
188         }
189
190         // Constant symbols are created late in the concurrent phase. Sort them
191         // to ensure a deterministic order.
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                 // if Pkgpath is unknown, cannot hash symbols with relocations, as it
207                 // may reference named symbols whose names are not fully expanded.
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                                 // We can use short hash only for symbols without relocations.
211                                 // Don't use short hash for type symbols, as they need special handling.
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) // 0 is invalid index
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                         // Assign special index for builtin symbols.
256                         // Don't do it when linking against shared libraries, as the runtime
257                         // may be in a different library.
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                         // for now, only support content-addressable symbols that are always locally defined.
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 // Returns whether s is a non-package symbol, which needs to be referenced
292 // by name instead of by index.
293 func isNonPkgSym(ctxt *Link, s *LSym) bool {
294         if ctxt.IsAsm && !s.Static() {
295                 // asm symbols are referenced by name only, except static symbols
296                 // which are file-local and can be referenced by index.
297                 return true
298         }
299         if ctxt.Flag_linkshared {
300                 // The referenced symbol may be in a different shared library so
301                 // the linker cannot see its index.
302                 return true
303         }
304         if s.Pkg == "_" {
305                 // The frontend uses package "_" to mark symbols that should not
306                 // be referenced by index, e.g. linkname'd symbols.
307                 return true
308         }
309         if s.DuplicateOK() {
310                 // Dupok symbol needs to be dedup'd by name.
311                 return true
312         }
313         return false
314 }
315
316 // StaticNamePref is the prefix the front end applies to static temporary
317 // variables. When turned into LSyms, these can be tagged as static so
318 // as to avoid inserting them into the linker's name lookup tables.
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 // Traverse symbols based on flag, call fn for each symbol.
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                 // NB: should it become necessary to walk aux sym reloc references
366                 // without walking the aux syms themselves, this can be changed.
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 // Traverse aux symbols, calling fn for each sym/aux pair.
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 }