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