]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/sym.go
all: implement wasmimport directive
[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/notsha256"
37         "cmd/internal/objabi"
38         "encoding/base64"
39         "fmt"
40         "internal/buildcfg"
41         "log"
42         "math"
43         "sort"
44 )
45
46 func Linknew(arch *LinkArch) *Link {
47         ctxt := new(Link)
48         ctxt.hash = make(map[string]*LSym)
49         ctxt.funchash = make(map[string]*LSym)
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 // LookupDerived looks up or creates the symbol with name derived from symbol s.
63 // The resulting symbol will be static iff s is.
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 // LookupStatic looks up the static symbol with name name.
72 // If it does not exist, it creates it.
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 // LookupABI looks up a symbol with the given ABI.
83 // If it does not exist, it creates it.
84 func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
85         return ctxt.LookupABIInit(name, abi, nil)
86 }
87
88 // LookupABIInit looks up a symbol with the given ABI.
89 // If it does not exist, it creates it and
90 // passes it to init for one-time initialization.
91 func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
92         var hash map[string]*LSym
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         ctxt.hashmu.Lock()
103         s := hash[name]
104         if s == nil {
105                 s = &LSym{Name: name}
106                 s.SetABI(abi)
107                 hash[name] = s
108                 if init != nil {
109                         init(s)
110                 }
111         }
112         ctxt.hashmu.Unlock()
113         return s
114 }
115
116 // Lookup looks up the symbol with name name.
117 // If it does not exist, it creates it.
118 func (ctxt *Link) Lookup(name string) *LSym {
119         return ctxt.LookupInit(name, nil)
120 }
121
122 // LookupInit looks up the symbol with name name.
123 // If it does not exist, it creates it and
124 // passes it to init for one-time initialization.
125 func (ctxt *Link) LookupInit(name string, init func(s *LSym)) *LSym {
126         ctxt.hashmu.Lock()
127         s := ctxt.hash[name]
128         if s == nil {
129                 s = &LSym{Name: name}
130                 ctxt.hash[name] = s
131                 if init != nil {
132                         init(s)
133                 }
134         }
135         ctxt.hashmu.Unlock()
136         return s
137 }
138
139 func (ctxt *Link) Float32Sym(f float32) *LSym {
140         i := math.Float32bits(f)
141         name := fmt.Sprintf("$f32.%08x", i)
142         return ctxt.LookupInit(name, func(s *LSym) {
143                 s.Size = 4
144                 s.WriteFloat32(ctxt, 0, f)
145                 s.Type = objabi.SRODATA
146                 s.Set(AttrLocal, true)
147                 s.Set(AttrContentAddressable, true)
148                 ctxt.constSyms = append(ctxt.constSyms, s)
149         })
150 }
151
152 func (ctxt *Link) Float64Sym(f float64) *LSym {
153         i := math.Float64bits(f)
154         name := fmt.Sprintf("$f64.%016x", i)
155         return ctxt.LookupInit(name, func(s *LSym) {
156                 s.Size = 8
157                 s.WriteFloat64(ctxt, 0, f)
158                 s.Type = objabi.SRODATA
159                 s.Set(AttrLocal, true)
160                 s.Set(AttrContentAddressable, true)
161                 ctxt.constSyms = append(ctxt.constSyms, s)
162         })
163 }
164
165 func (ctxt *Link) Int64Sym(i int64) *LSym {
166         name := fmt.Sprintf("$i64.%016x", uint64(i))
167         return ctxt.LookupInit(name, func(s *LSym) {
168                 s.Size = 8
169                 s.WriteInt(ctxt, 0, 8, i)
170                 s.Type = objabi.SRODATA
171                 s.Set(AttrLocal, true)
172                 s.Set(AttrContentAddressable, true)
173                 ctxt.constSyms = append(ctxt.constSyms, s)
174         })
175 }
176
177 // GCLocalsSym generates a content-addressable sym containing data.
178 func (ctxt *Link) GCLocalsSym(data []byte) *LSym {
179         sum := notsha256.Sum256(data)
180         str := base64.StdEncoding.EncodeToString(sum[:16])
181         return ctxt.LookupInit(fmt.Sprintf("gclocals·%s", str), func(lsym *LSym) {
182                 lsym.P = data
183                 lsym.Set(AttrContentAddressable, true)
184         })
185 }
186
187 // Assign index to symbols.
188 // asm is set to true if this is called by the assembler (i.e. not the compiler),
189 // in which case all the symbols are non-package (for now).
190 func (ctxt *Link) NumberSyms() {
191         if ctxt.Headtype == objabi.Haix {
192                 // Data must be sorted to keep a constant order in TOC symbols.
193                 // As they are created during Progedit, two symbols can be switched between
194                 // two different compilations. Therefore, BuildID will be different.
195                 // TODO: find a better place and optimize to only sort TOC symbols
196                 sort.Slice(ctxt.Data, func(i, j int) bool {
197                         return ctxt.Data[i].Name < ctxt.Data[j].Name
198                 })
199         }
200
201         // Constant symbols are created late in the concurrent phase. Sort them
202         // to ensure a deterministic order.
203         sort.Slice(ctxt.constSyms, func(i, j int) bool {
204                 return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name
205         })
206         ctxt.Data = append(ctxt.Data, ctxt.constSyms...)
207         ctxt.constSyms = nil
208
209         ctxt.pkgIdx = make(map[string]int32)
210         ctxt.defs = []*LSym{}
211         ctxt.hashed64defs = []*LSym{}
212         ctxt.hasheddefs = []*LSym{}
213         ctxt.nonpkgdefs = []*LSym{}
214
215         var idx, hashedidx, hashed64idx, nonpkgidx int32
216         ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) {
217                 // if Pkgpath is unknown, cannot hash symbols with relocations, as it
218                 // may reference named symbols whose names are not fully expanded.
219                 if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
220                         if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 {
221                                 // We can use short hash only for symbols without relocations.
222                                 // Don't use short hash for symbols that belong in a particular section
223                                 // or require special handling (such as type symbols).
224                                 s.PkgIdx = goobj.PkgIdxHashed64
225                                 s.SymIdx = hashed64idx
226                                 if hashed64idx != int32(len(ctxt.hashed64defs)) {
227                                         panic("bad index")
228                                 }
229                                 ctxt.hashed64defs = append(ctxt.hashed64defs, s)
230                                 hashed64idx++
231                         } else {
232                                 s.PkgIdx = goobj.PkgIdxHashed
233                                 s.SymIdx = hashedidx
234                                 if hashedidx != int32(len(ctxt.hasheddefs)) {
235                                         panic("bad index")
236                                 }
237                                 ctxt.hasheddefs = append(ctxt.hasheddefs, s)
238                                 hashedidx++
239                         }
240                 } else if isNonPkgSym(ctxt, s) {
241                         s.PkgIdx = goobj.PkgIdxNone
242                         s.SymIdx = nonpkgidx
243                         if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
244                                 panic("bad index")
245                         }
246                         ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
247                         nonpkgidx++
248                 } else {
249                         s.PkgIdx = goobj.PkgIdxSelf
250                         s.SymIdx = idx
251                         if idx != int32(len(ctxt.defs)) {
252                                 panic("bad index")
253                         }
254                         ctxt.defs = append(ctxt.defs, s)
255                         idx++
256                 }
257                 s.Set(AttrIndexed, true)
258         })
259
260         ipkg := int32(1) // 0 is invalid index
261         nonpkgdef := nonpkgidx
262         ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
263                 if rs.PkgIdx != goobj.PkgIdxInvalid {
264                         return
265                 }
266                 if !ctxt.Flag_linkshared {
267                         // Assign special index for builtin symbols.
268                         // Don't do it when linking against shared libraries, as the runtime
269                         // may be in a different library.
270                         if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
271                                 rs.PkgIdx = goobj.PkgIdxBuiltin
272                                 rs.SymIdx = int32(i)
273                                 rs.Set(AttrIndexed, true)
274                                 return
275                         }
276                 }
277                 pkg := rs.Pkg
278                 if rs.ContentAddressable() {
279                         // for now, only support content-addressable symbols that are always locally defined.
280                         panic("hashed refs unsupported for now")
281                 }
282                 if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
283                         rs.PkgIdx = goobj.PkgIdxNone
284                         rs.SymIdx = nonpkgidx
285                         rs.Set(AttrIndexed, true)
286                         if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
287                                 panic("bad index")
288                         }
289                         ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
290                         nonpkgidx++
291                         return
292                 }
293                 if k, ok := ctxt.pkgIdx[pkg]; ok {
294                         rs.PkgIdx = k
295                         return
296                 }
297                 rs.PkgIdx = ipkg
298                 ctxt.pkgIdx[pkg] = ipkg
299                 ipkg++
300         })
301 }
302
303 // Returns whether s is a non-package symbol, which needs to be referenced
304 // by name instead of by index.
305 func isNonPkgSym(ctxt *Link, s *LSym) bool {
306         if ctxt.IsAsm && !s.Static() {
307                 // asm symbols are referenced by name only, except static symbols
308                 // which are file-local and can be referenced by index.
309                 return true
310         }
311         if ctxt.Flag_linkshared {
312                 // The referenced symbol may be in a different shared library so
313                 // the linker cannot see its index.
314                 return true
315         }
316         if s.Pkg == "_" {
317                 // The frontend uses package "_" to mark symbols that should not
318                 // be referenced by index, e.g. linkname'd symbols.
319                 return true
320         }
321         if s.DuplicateOK() {
322                 // Dupok symbol needs to be dedup'd by name.
323                 return true
324         }
325         return false
326 }
327
328 // StaticNamePref is the prefix the front end applies to static temporary
329 // variables. When turned into LSyms, these can be tagged as static so
330 // as to avoid inserting them into the linker's name lookup tables.
331 const StaticNamePref = ".stmp_"
332
333 type traverseFlag uint32
334
335 const (
336         traverseDefs traverseFlag = 1 << iota
337         traverseRefs
338         traverseAux
339         traversePcdata
340
341         traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata
342 )
343
344 // Traverse symbols based on flag, call fn for each symbol.
345 func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
346         fnNoNil := func(s *LSym) {
347                 if s != nil {
348                         fn(s)
349                 }
350         }
351         lists := [][]*LSym{ctxt.Text, ctxt.Data}
352         files := ctxt.PosTable.FileTable()
353         for _, list := range lists {
354                 for _, s := range list {
355                         if flag&traverseDefs != 0 {
356                                 fn(s)
357                         }
358                         if flag&traverseRefs != 0 {
359                                 for _, r := range s.R {
360                                         fnNoNil(r.Sym)
361                                 }
362                         }
363                         if flag&traverseAux != 0 {
364                                 fnNoNil(s.Gotype)
365                                 if s.Type == objabi.STEXT {
366                                         f := func(parent *LSym, aux *LSym) {
367                                                 fn(aux)
368                                         }
369                                         ctxt.traverseFuncAux(flag, s, f, files)
370                                 }
371                         }
372                         if flag&traversePcdata != 0 && s.Type == objabi.STEXT {
373                                 fi := s.Func().Pcln
374                                 fnNoNil(fi.Pcsp)
375                                 fnNoNil(fi.Pcfile)
376                                 fnNoNil(fi.Pcline)
377                                 fnNoNil(fi.Pcinline)
378                                 for _, d := range fi.Pcdata {
379                                         fnNoNil(d)
380                                 }
381                         }
382                 }
383         }
384 }
385
386 func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym), files []string) {
387         fninfo := fsym.Func()
388         pc := &fninfo.Pcln
389         if flag&traverseAux == 0 {
390                 // NB: should it become necessary to walk aux sym reloc references
391                 // without walking the aux syms themselves, this can be changed.
392                 panic("should not be here")
393         }
394         for _, d := range pc.Funcdata {
395                 if d != nil {
396                         fn(fsym, d)
397                 }
398         }
399         usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
400         for f := range pc.UsedFiles {
401                 usedFiles = append(usedFiles, f)
402         }
403         sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
404         for _, f := range usedFiles {
405                 if filesym := ctxt.Lookup(files[f]); filesym != nil {
406                         fn(fsym, filesym)
407                 }
408         }
409         for _, call := range pc.InlTree.nodes {
410                 if call.Func != nil {
411                         fn(fsym, call.Func)
412                 }
413                 f, _ := ctxt.getFileSymbolAndLine(call.Pos)
414                 if filesym := ctxt.Lookup(f); filesym != nil {
415                         fn(fsym, filesym)
416                 }
417         }
418
419         auxsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym, fninfo.WasmImportSym}
420         for _, s := range auxsyms {
421                 if s == nil || s.Size == 0 {
422                         continue
423                 }
424                 fn(fsym, s)
425                 if flag&traverseRefs != 0 {
426                         for _, r := range s.R {
427                                 if r.Sym != nil {
428                                         fn(s, r.Sym)
429                                 }
430                         }
431                 }
432         }
433 }
434
435 // Traverse aux symbols, calling fn for each sym/aux pair.
436 func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
437         lists := [][]*LSym{ctxt.Text, ctxt.Data}
438         files := ctxt.PosTable.FileTable()
439         for _, list := range lists {
440                 for _, s := range list {
441                         if s.Gotype != nil {
442                                 if flag&traverseDefs != 0 {
443                                         fn(s, s.Gotype)
444                                 }
445                         }
446                         if s.Type != objabi.STEXT {
447                                 continue
448                         }
449                         ctxt.traverseFuncAux(flag, s, fn, files)
450                 }
451         }
452 }