1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Writing Go object files.
6
7package obj
8
9import (
10	"bytes"
11	"cmd/internal/bio"
12	"cmd/internal/goobj"
13	"cmd/internal/notsha256"
14	"cmd/internal/objabi"
15	"cmd/internal/sys"
16	"encoding/binary"
17	"fmt"
18	"internal/abi"
19	"io"
20	"log"
21	"os"
22	"path/filepath"
23	"sort"
24	"strings"
25)
26
27const UnlinkablePkg = "<unlinkable>" // invalid package path, used when compiled without -p flag
28
29// Entry point of writing new object file.
30func WriteObjFile(ctxt *Link, b *bio.Writer) {
31
32	debugAsmEmit(ctxt)
33
34	genFuncInfoSyms(ctxt)
35
36	w := writer{
37		Writer:  goobj.NewWriter(b),
38		ctxt:    ctxt,
39		pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
40	}
41
42	start := b.Offset()
43	w.init()
44
45	// Header
46	// We just reserve the space. We'll fill in the offsets later.
47	flags := uint32(0)
48	if ctxt.Flag_shared {
49		flags |= goobj.ObjFlagShared
50	}
51	if w.pkgpath == UnlinkablePkg {
52		flags |= goobj.ObjFlagUnlinkable
53	}
54	if w.pkgpath == "" {
55		log.Fatal("empty package path")
56	}
57	if ctxt.IsAsm {
58		flags |= goobj.ObjFlagFromAssembly
59	}
60	if ctxt.Std {
61		flags |= goobj.ObjFlagStd
62	}
63	h := goobj.Header{
64		Magic:       goobj.Magic,
65		Fingerprint: ctxt.Fingerprint,
66		Flags:       flags,
67	}
68	h.Write(w.Writer)
69
70	// String table
71	w.StringTable()
72
73	// Autolib
74	h.Offsets[goobj.BlkAutolib] = w.Offset()
75	for i := range ctxt.Imports {
76		ctxt.Imports[i].Write(w.Writer)
77	}
78
79	// Package references
80	h.Offsets[goobj.BlkPkgIdx] = w.Offset()
81	for _, pkg := range w.pkglist {
82		w.StringRef(pkg)
83	}
84
85	// File table (for DWARF and pcln generation).
86	h.Offsets[goobj.BlkFile] = w.Offset()
87	for _, f := range ctxt.PosTable.FileTable() {
88		w.StringRef(filepath.ToSlash(f))
89	}
90
91	// Symbol definitions
92	h.Offsets[goobj.BlkSymdef] = w.Offset()
93	for _, s := range ctxt.defs {
94		w.Sym(s)
95	}
96
97	// Short hashed symbol definitions
98	h.Offsets[goobj.BlkHashed64def] = w.Offset()
99	for _, s := range ctxt.hashed64defs {
100		w.Sym(s)
101	}
102
103	// Hashed symbol definitions
104	h.Offsets[goobj.BlkHasheddef] = w.Offset()
105	for _, s := range ctxt.hasheddefs {
106		w.Sym(s)
107	}
108
109	// Non-pkg symbol definitions
110	h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
111	for _, s := range ctxt.nonpkgdefs {
112		w.Sym(s)
113	}
114
115	// Non-pkg symbol references
116	h.Offsets[goobj.BlkNonpkgref] = w.Offset()
117	for _, s := range ctxt.nonpkgrefs {
118		w.Sym(s)
119	}
120
121	// Referenced package symbol flags
122	h.Offsets[goobj.BlkRefFlags] = w.Offset()
123	w.refFlags()
124
125	// Hashes
126	h.Offsets[goobj.BlkHash64] = w.Offset()
127	for _, s := range ctxt.hashed64defs {
128		w.Hash64(s)
129	}
130	h.Offsets[goobj.BlkHash] = w.Offset()
131	for _, s := range ctxt.hasheddefs {
132		w.Hash(s)
133	}
134	// TODO: hashedrefs unused/unsupported for now
135
136	// Reloc indexes
137	h.Offsets[goobj.BlkRelocIdx] = w.Offset()
138	nreloc := uint32(0)
139	lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
140	for _, list := range lists {
141		for _, s := range list {
142			w.Uint32(nreloc)
143			nreloc += uint32(len(s.R))
144		}
145	}
146	w.Uint32(nreloc)
147
148	// Symbol Info indexes
149	h.Offsets[goobj.BlkAuxIdx] = w.Offset()
150	naux := uint32(0)
151	for _, list := range lists {
152		for _, s := range list {
153			w.Uint32(naux)
154			naux += uint32(nAuxSym(s))
155		}
156	}
157	w.Uint32(naux)
158
159	// Data indexes
160	h.Offsets[goobj.BlkDataIdx] = w.Offset()
161	dataOff := int64(0)
162	for _, list := range lists {
163		for _, s := range list {
164			w.Uint32(uint32(dataOff))
165			dataOff += int64(len(s.P))
166			if file := s.File(); file != nil {
167				dataOff += int64(file.Size)
168			}
169		}
170	}
171	if int64(uint32(dataOff)) != dataOff {
172		log.Fatalf("data too large")
173	}
174	w.Uint32(uint32(dataOff))
175
176	// Relocs
177	h.Offsets[goobj.BlkReloc] = w.Offset()
178	for _, list := range lists {
179		for _, s := range list {
180			sort.Sort(relocByOff(s.R)) // some platforms (e.g. PE) requires relocations in address order
181			for i := range s.R {
182				w.Reloc(&s.R[i])
183			}
184		}
185	}
186
187	// Aux symbol info
188	h.Offsets[goobj.BlkAux] = w.Offset()
189	for _, list := range lists {
190		for _, s := range list {
191			w.Aux(s)
192		}
193	}
194
195	// Data
196	h.Offsets[goobj.BlkData] = w.Offset()
197	for _, list := range lists {
198		for _, s := range list {
199			w.Bytes(s.P)
200			if file := s.File(); file != nil {
201				w.writeFile(ctxt, file)
202			}
203		}
204	}
205
206	// Blocks used only by tools (objdump, nm).
207
208	// Referenced symbol names from other packages
209	h.Offsets[goobj.BlkRefName] = w.Offset()
210	w.refNames()
211
212	h.Offsets[goobj.BlkEnd] = w.Offset()
213
214	// Fix up block offsets in the header
215	end := start + int64(w.Offset())
216	b.MustSeek(start, 0)
217	h.Write(w.Writer)
218	b.MustSeek(end, 0)
219}
220
221type writer struct {
222	*goobj.Writer
223	filebuf []byte
224	ctxt    *Link
225	pkgpath string   // the package import path (escaped), "" if unknown
226	pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
227
228	// scratch space for writing (the Write methods escape
229	// as they are interface calls)
230	tmpSym      goobj.Sym
231	tmpReloc    goobj.Reloc
232	tmpAux      goobj.Aux
233	tmpHash64   goobj.Hash64Type
234	tmpHash     goobj.HashType
235	tmpRefFlags goobj.RefFlags
236	tmpRefName  goobj.RefName
237}
238
239// prepare package index list
240func (w *writer) init() {
241	w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
242	w.pkglist[0] = "" // dummy invalid package for index 0
243	for pkg, i := range w.ctxt.pkgIdx {
244		w.pkglist[i] = pkg
245	}
246}
247
248func (w *writer) writeFile(ctxt *Link, file *FileInfo) {
249	f, err := os.Open(file.Name)
250	if err != nil {
251		ctxt.Diag("%v", err)
252		return
253	}
254	defer f.Close()
255	if w.filebuf == nil {
256		w.filebuf = make([]byte, 1024)
257	}
258	buf := w.filebuf
259	written := int64(0)
260	for {
261		n, err := f.Read(buf)
262		w.Bytes(buf[:n])
263		written += int64(n)
264		if err == io.EOF {
265			break
266		}
267		if err != nil {
268			ctxt.Diag("%v", err)
269			return
270		}
271	}
272	if written != file.Size {
273		ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size)
274	}
275}
276
277func (w *writer) StringTable() {
278	w.AddString("")
279	for _, p := range w.ctxt.Imports {
280		w.AddString(p.Pkg)
281	}
282	for _, pkg := range w.pkglist {
283		w.AddString(pkg)
284	}
285	w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
286		// Don't put names of builtins into the string table (to save
287		// space).
288		if s.PkgIdx == goobj.PkgIdxBuiltin {
289			return
290		}
291		// TODO: this includes references of indexed symbols from other packages,
292		// for which the linker doesn't need the name. Consider moving them to
293		// a separate block (for tools only).
294		if w.ctxt.Flag_noRefName && s.PkgIdx < goobj.PkgIdxSpecial {
295			// Don't include them if Flag_noRefName
296			return
297		}
298		if strings.HasPrefix(s.Name, `"".`) {
299			w.ctxt.Diag("unqualified symbol name: %v", s.Name)
300		}
301		w.AddString(s.Name)
302	})
303
304	// All filenames are in the postable.
305	for _, f := range w.ctxt.PosTable.FileTable() {
306		w.AddString(filepath.ToSlash(f))
307	}
308}
309
310// cutoff is the maximum data section size permitted by the linker
311// (see issue #9862).
312const cutoff = int64(2e9) // 2 GB (or so; looks better in errors than 2^31)
313
314func (w *writer) Sym(s *LSym) {
315	name := s.Name
316	abi := uint16(s.ABI())
317	if s.Static() {
318		abi = goobj.SymABIstatic
319	}
320	flag := uint8(0)
321	if s.DuplicateOK() {
322		flag |= goobj.SymFlagDupok
323	}
324	if s.Local() {
325		flag |= goobj.SymFlagLocal
326	}
327	if s.MakeTypelink() {
328		flag |= goobj.SymFlagTypelink
329	}
330	if s.Leaf() {
331		flag |= goobj.SymFlagLeaf
332	}
333	if s.NoSplit() {
334		flag |= goobj.SymFlagNoSplit
335	}
336	if s.ReflectMethod() {
337		flag |= goobj.SymFlagReflectMethod
338	}
339	if strings.HasPrefix(s.Name, "type:") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
340		flag |= goobj.SymFlagGoType
341	}
342	flag2 := uint8(0)
343	if s.UsedInIface() {
344		flag2 |= goobj.SymFlagUsedInIface
345	}
346	if strings.HasPrefix(s.Name, "go:itab.") && s.Type == objabi.SRODATA {
347		flag2 |= goobj.SymFlagItab
348	}
349	if strings.HasPrefix(s.Name, w.ctxt.Pkgpath) && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath):], ".") && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath)+1:], objabi.GlobalDictPrefix) {
350		flag2 |= goobj.SymFlagDict
351	}
352	if s.IsPkgInit() {
353		flag2 |= goobj.SymFlagPkgInit
354	}
355	if s.IsLinkname() || (w.ctxt.IsAsm && name != "") || name == "main.main" {
356		// Assembly reference is treated the same as linkname,
357		// but not for unnamed (aux) symbols.
358		// The runtime linknames main.main.
359		flag2 |= goobj.SymFlagLinkname
360	}
361	if s.ABIWrapper() {
362		flag2 |= goobj.SymFlagABIWrapper
363	}
364	if strings.HasPrefix(name, "gofile..") {
365		name = filepath.ToSlash(name)
366	}
367	var align uint32
368	if fn := s.Func(); fn != nil {
369		align = uint32(fn.Align)
370	}
371	if s.ContentAddressable() && s.Size != 0 {
372		// We generally assume data symbols are naturally aligned
373		// (e.g. integer constants), except for strings and a few
374		// compiler-emitted funcdata. If we dedup a string symbol and
375		// a non-string symbol with the same content, we should keep
376		// the largest alignment.
377		// TODO: maybe the compiler could set the alignment for all
378		// data symbols more carefully.
379		switch {
380		case strings.HasPrefix(s.Name, "go:string."),
381			strings.HasPrefix(name, "type:.namedata."),
382			strings.HasPrefix(name, "type:.importpath."),
383			strings.HasSuffix(name, ".opendefer"),
384			strings.HasSuffix(name, ".arginfo0"),
385			strings.HasSuffix(name, ".arginfo1"),
386			strings.HasSuffix(name, ".argliveinfo"):
387			// These are just bytes, or varints.
388			align = 1
389		case strings.HasPrefix(name, "gclocals·"):
390			// It has 32-bit fields.
391			align = 4
392		default:
393			switch {
394			case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
395				align = 8
396			case s.Size%4 == 0:
397				align = 4
398			case s.Size%2 == 0:
399				align = 2
400			default:
401				align = 1
402			}
403		}
404	}
405	if s.Size > cutoff {
406		w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
407	}
408	o := &w.tmpSym
409	o.SetName(name, w.Writer)
410	o.SetABI(abi)
411	o.SetType(uint8(s.Type))
412	o.SetFlag(flag)
413	o.SetFlag2(flag2)
414	o.SetSiz(uint32(s.Size))
415	o.SetAlign(align)
416	o.Write(w.Writer)
417}
418
419func (w *writer) Hash64(s *LSym) {
420	if !s.ContentAddressable() || len(s.R) != 0 {
421		panic("Hash of non-content-addressable symbol")
422	}
423	w.tmpHash64 = contentHash64(s)
424	w.Bytes(w.tmpHash64[:])
425}
426
427func (w *writer) Hash(s *LSym) {
428	if !s.ContentAddressable() {
429		panic("Hash of non-content-addressable symbol")
430	}
431	w.tmpHash = w.contentHash(s)
432	w.Bytes(w.tmpHash[:])
433}
434
435// contentHashSection returns a mnemonic for s's section.
436// The goal is to prevent content-addressability from moving symbols between sections.
437// contentHashSection only distinguishes between sets of sections for which this matters.
438// Allowing flexibility increases the effectiveness of content-addressability.
439// But in some cases, such as doing addressing based on a base symbol,
440// we need to ensure that a symbol is always in a particular section.
441// Some of these conditions are duplicated in cmd/link/internal/ld.(*Link).symtab.
442// TODO: instead of duplicating them, have the compiler decide where symbols go.
443func contentHashSection(s *LSym) byte {
444	name := s.Name
445	if s.IsPcdata() {
446		return 'P'
447	}
448	if strings.HasPrefix(name, "gcargs.") ||
449		strings.HasPrefix(name, "gclocals.") ||
450		strings.HasPrefix(name, "gclocals·") ||
451		strings.HasSuffix(name, ".opendefer") ||
452		strings.HasSuffix(name, ".arginfo0") ||
453		strings.HasSuffix(name, ".arginfo1") ||
454		strings.HasSuffix(name, ".argliveinfo") ||
455		strings.HasSuffix(name, ".wrapinfo") ||
456		strings.HasSuffix(name, ".args_stackmap") ||
457		strings.HasSuffix(name, ".stkobj") {
458		return 'F' // go:func.* or go:funcrel.*
459	}
460	if strings.HasPrefix(name, "type:") {
461		return 'T'
462	}
463	return 0
464}
465
466func contentHash64(s *LSym) goobj.Hash64Type {
467	if contentHashSection(s) != 0 {
468		panic("short hash of non-default-section sym " + s.Name)
469	}
470	var b goobj.Hash64Type
471	copy(b[:], s.P)
472	return b
473}
474
475// Compute the content hash for a content-addressable symbol.
476// We build a content hash based on its content and relocations.
477// Depending on the category of the referenced symbol, we choose
478// different hash algorithms such that the hash is globally
479// consistent.
480//   - For referenced content-addressable symbol, its content hash
481//     is globally consistent.
482//   - For package symbol and builtin symbol, its local index is
483//     globally consistent.
484//   - For non-package symbol, its fully-expanded name is globally
485//     consistent. For now, we require we know the current package
486//     path so we can always expand symbol names. (Otherwise,
487//     symbols with relocations are not considered hashable.)
488//
489// For now, we assume there is no circular dependencies among
490// hashed symbols.
491func (w *writer) contentHash(s *LSym) goobj.HashType {
492	h := notsha256.New()
493	var tmp [14]byte
494
495	// Include the size of the symbol in the hash.
496	// This preserves the length of symbols, preventing the following two symbols
497	// from hashing the same:
498	//
499	//    [2]int{1,2} ≠ [10]int{1,2,0,0,0...}
500	//
501	// In this case, if the smaller symbol is alive, the larger is not kept unless
502	// needed.
503	binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
504	// Some symbols require being in separate sections.
505	tmp[8] = contentHashSection(s)
506	h.Write(tmp[:9])
507
508	// The compiler trims trailing zeros _sometimes_. We just do
509	// it always.
510	h.Write(bytes.TrimRight(s.P, "\x00"))
511	for i := range s.R {
512		r := &s.R[i]
513		binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
514		tmp[4] = r.Siz
515		tmp[5] = uint8(r.Type)
516		binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
517		h.Write(tmp[:])
518		rs := r.Sym
519		if rs == nil {
520			fmt.Printf("symbol: %s\n", s)
521			fmt.Printf("relocation: %#v\n", r)
522			panic("nil symbol target in relocation")
523		}
524		switch rs.PkgIdx {
525		case goobj.PkgIdxHashed64:
526			h.Write([]byte{0})
527			t := contentHash64(rs)
528			h.Write(t[:])
529		case goobj.PkgIdxHashed:
530			h.Write([]byte{1})
531			t := w.contentHash(rs)
532			h.Write(t[:])
533		case goobj.PkgIdxNone:
534			h.Write([]byte{2})
535			io.WriteString(h, rs.Name) // name is already expanded at this point
536		case goobj.PkgIdxBuiltin:
537			h.Write([]byte{3})
538			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
539			h.Write(tmp[:4])
540		case goobj.PkgIdxSelf:
541			io.WriteString(h, w.pkgpath)
542			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
543			h.Write(tmp[:4])
544		default:
545			io.WriteString(h, rs.Pkg)
546			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
547			h.Write(tmp[:4])
548		}
549	}
550	var b goobj.HashType
551	copy(b[:], h.Sum(nil))
552	return b
553}
554
555func makeSymRef(s *LSym) goobj.SymRef {
556	if s == nil {
557		return goobj.SymRef{}
558	}
559	if s.PkgIdx == 0 || !s.Indexed() {
560		fmt.Printf("unindexed symbol reference: %v\n", s)
561		panic("unindexed symbol reference")
562	}
563	return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
564}
565
566func (w *writer) Reloc(r *Reloc) {
567	o := &w.tmpReloc
568	o.SetOff(r.Off)
569	o.SetSiz(r.Siz)
570	o.SetType(uint16(r.Type))
571	o.SetAdd(r.Add)
572	o.SetSym(makeSymRef(r.Sym))
573	o.Write(w.Writer)
574}
575
576func (w *writer) aux1(typ uint8, rs *LSym) {
577	o := &w.tmpAux
578	o.SetType(typ)
579	o.SetSym(makeSymRef(rs))
580	o.Write(w.Writer)
581}
582
583func (w *writer) Aux(s *LSym) {
584	if s.Gotype != nil {
585		w.aux1(goobj.AuxGotype, s.Gotype)
586	}
587	if fn := s.Func(); fn != nil {
588		w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
589
590		for _, d := range fn.Pcln.Funcdata {
591			w.aux1(goobj.AuxFuncdata, d)
592		}
593
594		if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
595			w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
596		}
597		if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
598			w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
599		}
600		if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
601			w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
602		}
603		if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
604			w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
605		}
606		if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
607			w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
608		}
609		if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
610			w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
611		}
612		if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
613			w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
614		}
615		if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
616			w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
617		}
618		if fn.sehUnwindInfoSym != nil && fn.sehUnwindInfoSym.Size != 0 {
619			w.aux1(goobj.AuxSehUnwindInfo, fn.sehUnwindInfoSym)
620		}
621		for _, pcSym := range fn.Pcln.Pcdata {
622			w.aux1(goobj.AuxPcdata, pcSym)
623		}
624		if fn.WasmImportSym != nil {
625			if fn.WasmImportSym.Size == 0 {
626				panic("wasmimport aux sym must have non-zero size")
627			}
628			w.aux1(goobj.AuxWasmImport, fn.WasmImportSym)
629		}
630	} else if v := s.VarInfo(); v != nil {
631		if v.dwarfInfoSym != nil && v.dwarfInfoSym.Size != 0 {
632			w.aux1(goobj.AuxDwarfInfo, v.dwarfInfoSym)
633		}
634	}
635}
636
637// Emits flags of referenced indexed symbols.
638func (w *writer) refFlags() {
639	seen := make(map[*LSym]bool)
640	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
641		switch rs.PkgIdx {
642		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
643			return
644		case goobj.PkgIdxInvalid:
645			panic("unindexed symbol reference")
646		}
647		if seen[rs] {
648			return
649		}
650		seen[rs] = true
651		symref := makeSymRef(rs)
652		flag2 := uint8(0)
653		if rs.UsedInIface() {
654			flag2 |= goobj.SymFlagUsedInIface
655		}
656		if flag2 == 0 {
657			return // no need to write zero flags
658		}
659		o := &w.tmpRefFlags
660		o.SetSym(symref)
661		o.SetFlag2(flag2)
662		o.Write(w.Writer)
663	})
664}
665
666// Emits names of referenced indexed symbols, used by tools (objdump, nm)
667// only.
668func (w *writer) refNames() {
669	if w.ctxt.Flag_noRefName {
670		return
671	}
672	seen := make(map[*LSym]bool)
673	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
674		switch rs.PkgIdx {
675		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
676			return
677		case goobj.PkgIdxInvalid:
678			panic("unindexed symbol reference")
679		}
680		if seen[rs] {
681			return
682		}
683		seen[rs] = true
684		symref := makeSymRef(rs)
685		o := &w.tmpRefName
686		o.SetSym(symref)
687		o.SetName(rs.Name, w.Writer)
688		o.Write(w.Writer)
689	})
690	// TODO: output in sorted order?
691	// Currently tools (cmd/internal/goobj package) doesn't use mmap,
692	// and it just read it into a map in memory upfront. If it uses
693	// mmap, if the output is sorted, it probably could avoid reading
694	// into memory and just do lookups in the mmap'd object file.
695}
696
697// return the number of aux symbols s have.
698func nAuxSym(s *LSym) int {
699	n := 0
700	if s.Gotype != nil {
701		n++
702	}
703	if fn := s.Func(); fn != nil {
704		// FuncInfo is an aux symbol, each Funcdata is an aux symbol
705		n += 1 + len(fn.Pcln.Funcdata)
706		if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
707			n++
708		}
709		if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
710			n++
711		}
712		if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
713			n++
714		}
715		if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
716			n++
717		}
718		if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
719			n++
720		}
721		if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
722			n++
723		}
724		if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
725			n++
726		}
727		if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
728			n++
729		}
730		if fn.sehUnwindInfoSym != nil && fn.sehUnwindInfoSym.Size != 0 {
731			n++
732		}
733		n += len(fn.Pcln.Pcdata)
734		if fn.WasmImport != nil {
735			if fn.WasmImportSym == nil || fn.WasmImportSym.Size == 0 {
736				panic("wasmimport aux sym must exist and have non-zero size")
737			}
738			n++
739		}
740	} else if v := s.VarInfo(); v != nil {
741		if v.dwarfInfoSym != nil && v.dwarfInfoSym.Size != 0 {
742			n++
743		}
744	}
745	return n
746}
747
748// generate symbols for FuncInfo.
749func genFuncInfoSyms(ctxt *Link) {
750	infosyms := make([]*LSym, 0, len(ctxt.Text))
751	var b bytes.Buffer
752	symidx := int32(len(ctxt.defs))
753	for _, s := range ctxt.Text {
754		fn := s.Func()
755		if fn == nil {
756			continue
757		}
758		o := goobj.FuncInfo{
759			Args:      uint32(fn.Args),
760			Locals:    uint32(fn.Locals),
761			FuncID:    fn.FuncID,
762			FuncFlag:  fn.FuncFlag,
763			StartLine: fn.StartLine,
764		}
765		pc := &fn.Pcln
766		i := 0
767		o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
768		for f := range pc.UsedFiles {
769			o.File[i] = f
770			i++
771		}
772		sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
773		o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
774		for i, inl := range pc.InlTree.nodes {
775			f, l := ctxt.getFileIndexAndLine(inl.Pos)
776			o.InlTree[i] = goobj.InlTreeNode{
777				Parent:   int32(inl.Parent),
778				File:     goobj.CUFileIndex(f),
779				Line:     l,
780				Func:     makeSymRef(inl.Func),
781				ParentPC: inl.ParentPC,
782			}
783		}
784
785		o.Write(&b)
786		p := b.Bytes()
787		isym := &LSym{
788			Type:   objabi.SDATA, // for now, I don't think it matters
789			PkgIdx: goobj.PkgIdxSelf,
790			SymIdx: symidx,
791			P:      append([]byte(nil), p...),
792			Size:   int64(len(p)),
793		}
794		isym.Set(AttrIndexed, true)
795		symidx++
796		infosyms = append(infosyms, isym)
797		fn.FuncInfoSym = isym
798		b.Reset()
799
800		auxsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym, fn.WasmImportSym}
801		for _, s := range auxsyms {
802			if s == nil || s.Size == 0 {
803				continue
804			}
805			if s.OnList() {
806				panic("a symbol is added to defs multiple times")
807			}
808			s.PkgIdx = goobj.PkgIdxSelf
809			s.SymIdx = symidx
810			s.Set(AttrIndexed, true)
811			s.Set(AttrOnList, true)
812			symidx++
813			infosyms = append(infosyms, s)
814		}
815	}
816	ctxt.defs = append(ctxt.defs, infosyms...)
817}
818
819func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
820	// Most aux symbols (ex: funcdata) are not interesting--
821	// pick out just the DWARF ones for now.
822	switch aux.Type {
823	case objabi.SDWARFLOC,
824		objabi.SDWARFFCN,
825		objabi.SDWARFABSFCN,
826		objabi.SDWARFLINES,
827		objabi.SDWARFRANGE,
828		objabi.SDWARFVAR:
829	default:
830		return
831	}
832	ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
833}
834
835func debugAsmEmit(ctxt *Link) {
836	if ctxt.Debugasm > 0 {
837		ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
838		if ctxt.Debugasm > 1 {
839			fn := func(par *LSym, aux *LSym) {
840				writeAuxSymDebug(ctxt, par, aux)
841			}
842			ctxt.traverseAuxSyms(traverseAux, fn)
843		}
844	}
845}
846
847func (ctxt *Link) writeSymDebug(s *LSym) {
848	ctxt.writeSymDebugNamed(s, s.Name)
849}
850
851func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
852	ver := ""
853	if ctxt.Debugasm > 1 {
854		ver = fmt.Sprintf("<%d>", s.ABI())
855		if ctxt.Debugasm > 2 {
856			ver += fmt.Sprintf("<idx %d %d>", s.PkgIdx, s.SymIdx)
857		}
858	}
859	fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
860	if s.Type != 0 {
861		fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
862	}
863	if s.Static() {
864		fmt.Fprint(ctxt.Bso, "static ")
865	}
866	if s.DuplicateOK() {
867		fmt.Fprintf(ctxt.Bso, "dupok ")
868	}
869	if s.CFunc() {
870		fmt.Fprintf(ctxt.Bso, "cfunc ")
871	}
872	if s.NoSplit() {
873		fmt.Fprintf(ctxt.Bso, "nosplit ")
874	}
875	if s.Func() != nil && s.Func().FuncFlag&abi.FuncFlagTopFrame != 0 {
876		fmt.Fprintf(ctxt.Bso, "topframe ")
877	}
878	if s.Func() != nil && s.Func().FuncFlag&abi.FuncFlagAsm != 0 {
879		fmt.Fprintf(ctxt.Bso, "asm ")
880	}
881	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
882	if s.Type == objabi.STEXT {
883		fn := s.Func()
884		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x align=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID), uint64(fn.Align))
885		if s.Leaf() {
886			fmt.Fprintf(ctxt.Bso, " leaf")
887		}
888	}
889	fmt.Fprintf(ctxt.Bso, "\n")
890	if s.Type == objabi.STEXT {
891		for p := s.Func().Text; p != nil; p = p.Link {
892			fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
893			if ctxt.Debugasm > 1 {
894				io.WriteString(ctxt.Bso, p.String())
895			} else {
896				p.InnermostString(ctxt.Bso)
897			}
898			fmt.Fprintln(ctxt.Bso)
899		}
900	}
901	for i := 0; i < len(s.P); i += 16 {
902		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
903		j := i
904		for ; j < i+16 && j < len(s.P); j++ {
905			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
906		}
907		for ; j < i+16; j++ {
908			fmt.Fprintf(ctxt.Bso, "   ")
909		}
910		fmt.Fprintf(ctxt.Bso, "  ")
911		for j = i; j < i+16 && j < len(s.P); j++ {
912			c := int(s.P[j])
913			b := byte('.')
914			if ' ' <= c && c <= 0x7e {
915				b = byte(c)
916			}
917			ctxt.Bso.WriteByte(b)
918		}
919
920		fmt.Fprintf(ctxt.Bso, "\n")
921	}
922
923	sort.Sort(relocByOff(s.R)) // generate stable output
924	for _, r := range s.R {
925		name := ""
926		ver := ""
927		if r.Sym != nil {
928			name = r.Sym.Name
929			if ctxt.Debugasm > 1 {
930				ver = fmt.Sprintf("<%d>", r.Sym.ABI())
931			}
932		} else if r.Type == objabi.R_TLS_LE {
933			name = "TLS"
934		}
935		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
936			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%v %s%s+%x\n", int(r.Off), r.Siz, r.Type, name, ver, uint64(r.Add))
937		} else {
938			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%v %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
939		}
940	}
941}
942
943// relocByOff sorts relocations by their offsets.
944type relocByOff []Reloc
945
946func (x relocByOff) Len() int           { return len(x) }
947func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
948func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
949