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