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 ([email protected])
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 ([email protected])
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
32package obj
33
34import (
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
47func 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// LookupDerived looks up or creates the symbol with name derived from symbol s.
64// The resulting symbol will be static iff s is.
65func (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// LookupStatic looks up the static symbol with name name.
73// If it does not exist, it creates it.
74func (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// LookupABI looks up a symbol with the given ABI.
84// If it does not exist, it creates it.
85func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
86	return ctxt.LookupABIInit(name, abi, nil)
87}
88
89// LookupABIInit looks up a symbol with the given ABI.
90// If it does not exist, it creates it and
91// passes it to init for one-time initialization.
92func (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// Lookup looks up the symbol with name name.
118// If it does not exist, it creates it.
119func (ctxt *Link) Lookup(name string) *LSym {
120	return ctxt.LookupInit(name, nil)
121}
122
123// LookupInit looks up the symbol with name name.
124// If it does not exist, it creates it and
125// passes it to init for one-time initialization.
126func (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
140func (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
153func (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
166func (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
178func (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
190func (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// GCLocalsSym generates a content-addressable sym containing data.
209func (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// Assign index to symbols.
219// asm is set to true if this is called by the assembler (i.e. not the compiler),
220// in which case all the symbols are non-package (for now).
221func (ctxt *Link) NumberSyms() {
222	if ctxt.Pkgpath == "" {
223		panic("NumberSyms called without package path")
224	}
225
226	if ctxt.Headtype == objabi.Haix {
227		// Data must be in a reliable order for reproducible builds.
228		// The original entries are in a reliable order, but the TOC symbols
229		// that are added in Progedit are added by different goroutines
230		// that can be scheduled independently. We need to reorder those
231		// symbols reliably. Sort by name but use a stable sort, so that
232		// any original entries with the same name (all DWARFVAR symbols
233		// have empty names but different relocation sets) are not shuffled.
234		// TODO: Find a better place and optimize to only sort TOC symbols.
235		sort.SliceStable(ctxt.Data, func(i, j int) bool {
236			return ctxt.Data[i].Name < ctxt.Data[j].Name
237		})
238	}
239
240	// Constant symbols are created late in the concurrent phase. Sort them
241	// to ensure a deterministic order.
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	// So are SEH symbols.
249	sort.Slice(ctxt.SEHSyms, func(i, j int) bool {
250		return ctxt.SEHSyms[i].Name < ctxt.SEHSyms[j].Name
251	})
252	ctxt.Data = append(ctxt.Data, ctxt.SEHSyms...)
253	ctxt.SEHSyms = nil
254
255	ctxt.pkgIdx = make(map[string]int32)
256	ctxt.defs = []*LSym{}
257	ctxt.hashed64defs = []*LSym{}
258	ctxt.hasheddefs = []*LSym{}
259	ctxt.nonpkgdefs = []*LSym{}
260
261	var idx, hashedidx, hashed64idx, nonpkgidx int32
262	ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) {
263		if s.ContentAddressable() {
264			if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 {
265				// We can use short hash only for symbols without relocations.
266				// Don't use short hash for symbols that belong in a particular section
267				// or require special handling (such as type symbols).
268				s.PkgIdx = goobj.PkgIdxHashed64
269				s.SymIdx = hashed64idx
270				if hashed64idx != int32(len(ctxt.hashed64defs)) {
271					panic("bad index")
272				}
273				ctxt.hashed64defs = append(ctxt.hashed64defs, s)
274				hashed64idx++
275			} else {
276				s.PkgIdx = goobj.PkgIdxHashed
277				s.SymIdx = hashedidx
278				if hashedidx != int32(len(ctxt.hasheddefs)) {
279					panic("bad index")
280				}
281				ctxt.hasheddefs = append(ctxt.hasheddefs, s)
282				hashedidx++
283			}
284		} else if isNonPkgSym(ctxt, s) {
285			s.PkgIdx = goobj.PkgIdxNone
286			s.SymIdx = nonpkgidx
287			if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
288				panic("bad index")
289			}
290			ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
291			nonpkgidx++
292		} else {
293			s.PkgIdx = goobj.PkgIdxSelf
294			s.SymIdx = idx
295			if idx != int32(len(ctxt.defs)) {
296				panic("bad index")
297			}
298			ctxt.defs = append(ctxt.defs, s)
299			idx++
300		}
301		s.Set(AttrIndexed, true)
302	})
303
304	ipkg := int32(1) // 0 is invalid index
305	nonpkgdef := nonpkgidx
306	ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
307		if rs.PkgIdx != goobj.PkgIdxInvalid {
308			return
309		}
310		if !ctxt.Flag_linkshared {
311			// Assign special index for builtin symbols.
312			// Don't do it when linking against shared libraries, as the runtime
313			// may be in a different library.
314			if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
315				rs.PkgIdx = goobj.PkgIdxBuiltin
316				rs.SymIdx = int32(i)
317				rs.Set(AttrIndexed, true)
318				return
319			}
320		}
321		pkg := rs.Pkg
322		if rs.ContentAddressable() {
323			// for now, only support content-addressable symbols that are always locally defined.
324			panic("hashed refs unsupported for now")
325		}
326		if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
327			rs.PkgIdx = goobj.PkgIdxNone
328			rs.SymIdx = nonpkgidx
329			rs.Set(AttrIndexed, true)
330			if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
331				panic("bad index")
332			}
333			ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
334			nonpkgidx++
335			return
336		}
337		if k, ok := ctxt.pkgIdx[pkg]; ok {
338			rs.PkgIdx = k
339			return
340		}
341		rs.PkgIdx = ipkg
342		ctxt.pkgIdx[pkg] = ipkg
343		ipkg++
344	})
345}
346
347// Returns whether s is a non-package symbol, which needs to be referenced
348// by name instead of by index.
349func isNonPkgSym(ctxt *Link, s *LSym) bool {
350	if ctxt.IsAsm && !s.Static() {
351		// asm symbols are referenced by name only, except static symbols
352		// which are file-local and can be referenced by index.
353		return true
354	}
355	if ctxt.Flag_linkshared {
356		// The referenced symbol may be in a different shared library so
357		// the linker cannot see its index.
358		return true
359	}
360	if s.Pkg == "_" {
361		// The frontend uses package "_" to mark symbols that should not
362		// be referenced by index, e.g. linkname'd symbols.
363		return true
364	}
365	if s.DuplicateOK() {
366		// Dupok symbol needs to be dedup'd by name.
367		return true
368	}
369	return false
370}
371
372// StaticNamePref is the prefix the front end applies to static temporary
373// variables. When turned into LSyms, these can be tagged as static so
374// as to avoid inserting them into the linker's name lookup tables.
375const StaticNamePref = ".stmp_"
376
377type traverseFlag uint32
378
379const (
380	traverseDefs traverseFlag = 1 << iota
381	traverseRefs
382	traverseAux
383	traversePcdata
384
385	traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata
386)
387
388// Traverse symbols based on flag, call fn for each symbol.
389func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
390	fnNoNil := func(s *LSym) {
391		if s != nil {
392			fn(s)
393		}
394	}
395	lists := [][]*LSym{ctxt.Text, ctxt.Data}
396	files := ctxt.PosTable.FileTable()
397	for _, list := range lists {
398		for _, s := range list {
399			if flag&traverseDefs != 0 {
400				fn(s)
401			}
402			if flag&traverseRefs != 0 {
403				for _, r := range s.R {
404					fnNoNil(r.Sym)
405				}
406			}
407			if flag&traverseAux != 0 {
408				fnNoNil(s.Gotype)
409				if s.Type == objabi.STEXT {
410					f := func(parent *LSym, aux *LSym) {
411						fn(aux)
412					}
413					ctxt.traverseFuncAux(flag, s, f, files)
414				} else if v := s.VarInfo(); v != nil {
415					fnNoNil(v.dwarfInfoSym)
416				}
417			}
418			if flag&traversePcdata != 0 && s.Type == objabi.STEXT {
419				fi := s.Func().Pcln
420				fnNoNil(fi.Pcsp)
421				fnNoNil(fi.Pcfile)
422				fnNoNil(fi.Pcline)
423				fnNoNil(fi.Pcinline)
424				for _, d := range fi.Pcdata {
425					fnNoNil(d)
426				}
427			}
428		}
429	}
430}
431
432func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym), files []string) {
433	fninfo := fsym.Func()
434	pc := &fninfo.Pcln
435	if flag&traverseAux == 0 {
436		// NB: should it become necessary to walk aux sym reloc references
437		// without walking the aux syms themselves, this can be changed.
438		panic("should not be here")
439	}
440	for _, d := range pc.Funcdata {
441		if d != nil {
442			fn(fsym, d)
443		}
444	}
445	usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
446	for f := range pc.UsedFiles {
447		usedFiles = append(usedFiles, f)
448	}
449	sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
450	for _, f := range usedFiles {
451		if filesym := ctxt.Lookup(files[f]); filesym != nil {
452			fn(fsym, filesym)
453		}
454	}
455	for _, call := range pc.InlTree.nodes {
456		if call.Func != nil {
457			fn(fsym, call.Func)
458		}
459	}
460
461	auxsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym, fninfo.WasmImportSym, fninfo.sehUnwindInfoSym}
462	for _, s := range auxsyms {
463		if s == nil || s.Size == 0 {
464			continue
465		}
466		fn(fsym, s)
467		if flag&traverseRefs != 0 {
468			for _, r := range s.R {
469				if r.Sym != nil {
470					fn(s, r.Sym)
471				}
472			}
473		}
474	}
475}
476
477// Traverse aux symbols, calling fn for each sym/aux pair.
478func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
479	lists := [][]*LSym{ctxt.Text, ctxt.Data}
480	files := ctxt.PosTable.FileTable()
481	for _, list := range lists {
482		for _, s := range list {
483			if s.Gotype != nil {
484				if flag&traverseDefs != 0 {
485					fn(s, s.Gotype)
486				}
487			}
488			if s.Type == objabi.STEXT {
489				ctxt.traverseFuncAux(flag, s, fn, files)
490			} else if v := s.VarInfo(); v != nil && v.dwarfInfoSym != nil {
491				fn(s, v.dwarfInfoSym)
492			}
493		}
494	}
495}
496