podman

Форк
0
755 строк · 18.4 Кб
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
	"github.com/twitchyliquid64/golang-asm/bio"
12
	"github.com/twitchyliquid64/golang-asm/goobj"
13
	"github.com/twitchyliquid64/golang-asm/objabi"
14
	"github.com/twitchyliquid64/golang-asm/sys"
15
	"crypto/sha1"
16
	"encoding/binary"
17
	"fmt"
18
	"io"
19
	"path/filepath"
20
	"sort"
21
	"strings"
22
)
23

24
// Entry point of writing new object file.
25
func WriteObjFile(ctxt *Link, b *bio.Writer) {
26

27
	debugAsmEmit(ctxt)
28

29
	genFuncInfoSyms(ctxt)
30

31
	w := writer{
32
		Writer:  goobj.NewWriter(b),
33
		ctxt:    ctxt,
34
		pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
35
	}
36

37
	start := b.Offset()
38
	w.init()
39

40
	// Header
41
	// We just reserve the space. We'll fill in the offsets later.
42
	flags := uint32(0)
43
	if ctxt.Flag_shared {
44
		flags |= goobj.ObjFlagShared
45
	}
46
	if w.pkgpath == "" {
47
		flags |= goobj.ObjFlagNeedNameExpansion
48
	}
49
	if ctxt.IsAsm {
50
		flags |= goobj.ObjFlagFromAssembly
51
	}
52
	h := goobj.Header{
53
		Magic:       goobj.Magic,
54
		Fingerprint: ctxt.Fingerprint,
55
		Flags:       flags,
56
	}
57
	h.Write(w.Writer)
58

59
	// String table
60
	w.StringTable()
61

62
	// Autolib
63
	h.Offsets[goobj.BlkAutolib] = w.Offset()
64
	for i := range ctxt.Imports {
65
		ctxt.Imports[i].Write(w.Writer)
66
	}
67

68
	// Package references
69
	h.Offsets[goobj.BlkPkgIdx] = w.Offset()
70
	for _, pkg := range w.pkglist {
71
		w.StringRef(pkg)
72
	}
73

74
	// File table (for DWARF and pcln generation).
75
	h.Offsets[goobj.BlkFile] = w.Offset()
76
	for _, f := range ctxt.PosTable.FileTable() {
77
		w.StringRef(filepath.ToSlash(f))
78
	}
79

80
	// Symbol definitions
81
	h.Offsets[goobj.BlkSymdef] = w.Offset()
82
	for _, s := range ctxt.defs {
83
		w.Sym(s)
84
	}
85

86
	// Short hashed symbol definitions
87
	h.Offsets[goobj.BlkHashed64def] = w.Offset()
88
	for _, s := range ctxt.hashed64defs {
89
		w.Sym(s)
90
	}
91

92
	// Hashed symbol definitions
93
	h.Offsets[goobj.BlkHasheddef] = w.Offset()
94
	for _, s := range ctxt.hasheddefs {
95
		w.Sym(s)
96
	}
97

98
	// Non-pkg symbol definitions
99
	h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
100
	for _, s := range ctxt.nonpkgdefs {
101
		w.Sym(s)
102
	}
103

104
	// Non-pkg symbol references
105
	h.Offsets[goobj.BlkNonpkgref] = w.Offset()
106
	for _, s := range ctxt.nonpkgrefs {
107
		w.Sym(s)
108
	}
109

110
	// Referenced package symbol flags
111
	h.Offsets[goobj.BlkRefFlags] = w.Offset()
112
	w.refFlags()
113

114
	// Hashes
115
	h.Offsets[goobj.BlkHash64] = w.Offset()
116
	for _, s := range ctxt.hashed64defs {
117
		w.Hash64(s)
118
	}
119
	h.Offsets[goobj.BlkHash] = w.Offset()
120
	for _, s := range ctxt.hasheddefs {
121
		w.Hash(s)
122
	}
123
	// TODO: hashedrefs unused/unsupported for now
124

125
	// Reloc indexes
126
	h.Offsets[goobj.BlkRelocIdx] = w.Offset()
127
	nreloc := uint32(0)
128
	lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
129
	for _, list := range lists {
130
		for _, s := range list {
131
			w.Uint32(nreloc)
132
			nreloc += uint32(len(s.R))
133
		}
134
	}
135
	w.Uint32(nreloc)
136

137
	// Symbol Info indexes
138
	h.Offsets[goobj.BlkAuxIdx] = w.Offset()
139
	naux := uint32(0)
140
	for _, list := range lists {
141
		for _, s := range list {
142
			w.Uint32(naux)
143
			naux += uint32(nAuxSym(s))
144
		}
145
	}
146
	w.Uint32(naux)
147

148
	// Data indexes
149
	h.Offsets[goobj.BlkDataIdx] = w.Offset()
150
	dataOff := uint32(0)
151
	for _, list := range lists {
152
		for _, s := range list {
153
			w.Uint32(dataOff)
154
			dataOff += uint32(len(s.P))
155
		}
156
	}
157
	w.Uint32(dataOff)
158

159
	// Relocs
160
	h.Offsets[goobj.BlkReloc] = w.Offset()
161
	for _, list := range lists {
162
		for _, s := range list {
163
			for i := range s.R {
164
				w.Reloc(&s.R[i])
165
			}
166
		}
167
	}
168

169
	// Aux symbol info
170
	h.Offsets[goobj.BlkAux] = w.Offset()
171
	for _, list := range lists {
172
		for _, s := range list {
173
			w.Aux(s)
174
		}
175
	}
176

177
	// Data
178
	h.Offsets[goobj.BlkData] = w.Offset()
179
	for _, list := range lists {
180
		for _, s := range list {
181
			w.Bytes(s.P)
182
		}
183
	}
184

185
	// Pcdata
186
	h.Offsets[goobj.BlkPcdata] = w.Offset()
187
	for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
188
		if s.Func != nil {
189
			pc := &s.Func.Pcln
190
			w.Bytes(pc.Pcsp.P)
191
			w.Bytes(pc.Pcfile.P)
192
			w.Bytes(pc.Pcline.P)
193
			w.Bytes(pc.Pcinline.P)
194
			for i := range pc.Pcdata {
195
				w.Bytes(pc.Pcdata[i].P)
196
			}
197
		}
198
	}
199

200
	// Blocks used only by tools (objdump, nm).
201

202
	// Referenced symbol names from other packages
203
	h.Offsets[goobj.BlkRefName] = w.Offset()
204
	w.refNames()
205

206
	h.Offsets[goobj.BlkEnd] = w.Offset()
207

208
	// Fix up block offsets in the header
209
	end := start + int64(w.Offset())
210
	b.MustSeek(start, 0)
211
	h.Write(w.Writer)
212
	b.MustSeek(end, 0)
213
}
214

215
type writer struct {
216
	*goobj.Writer
217
	ctxt    *Link
218
	pkgpath string   // the package import path (escaped), "" if unknown
219
	pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
220
}
221

222
// prepare package index list
223
func (w *writer) init() {
224
	w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
225
	w.pkglist[0] = "" // dummy invalid package for index 0
226
	for pkg, i := range w.ctxt.pkgIdx {
227
		w.pkglist[i] = pkg
228
	}
229
}
230

231
func (w *writer) StringTable() {
232
	w.AddString("")
233
	for _, p := range w.ctxt.Imports {
234
		w.AddString(p.Pkg)
235
	}
236
	for _, pkg := range w.pkglist {
237
		w.AddString(pkg)
238
	}
239
	w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
240
		// TODO: this includes references of indexed symbols from other packages,
241
		// for which the linker doesn't need the name. Consider moving them to
242
		// a separate block (for tools only).
243
		if w.pkgpath != "" {
244
			s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
245
		}
246
		// Don't put names of builtins into the string table (to save
247
		// space).
248
		if s.PkgIdx == goobj.PkgIdxBuiltin {
249
			return
250
		}
251
		w.AddString(s.Name)
252
	})
253

254
	// All filenames are in the postable.
255
	for _, f := range w.ctxt.PosTable.FileTable() {
256
		w.AddString(filepath.ToSlash(f))
257
	}
258
}
259

260
func (w *writer) Sym(s *LSym) {
261
	abi := uint16(s.ABI())
262
	if s.Static() {
263
		abi = goobj.SymABIstatic
264
	}
265
	flag := uint8(0)
266
	if s.DuplicateOK() {
267
		flag |= goobj.SymFlagDupok
268
	}
269
	if s.Local() {
270
		flag |= goobj.SymFlagLocal
271
	}
272
	if s.MakeTypelink() {
273
		flag |= goobj.SymFlagTypelink
274
	}
275
	if s.Leaf() {
276
		flag |= goobj.SymFlagLeaf
277
	}
278
	if s.NoSplit() {
279
		flag |= goobj.SymFlagNoSplit
280
	}
281
	if s.ReflectMethod() {
282
		flag |= goobj.SymFlagReflectMethod
283
	}
284
	if s.TopFrame() {
285
		flag |= goobj.SymFlagTopFrame
286
	}
287
	if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
288
		flag |= goobj.SymFlagGoType
289
	}
290
	flag2 := uint8(0)
291
	if s.UsedInIface() {
292
		flag2 |= goobj.SymFlagUsedInIface
293
	}
294
	if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
295
		flag2 |= goobj.SymFlagItab
296
	}
297
	name := s.Name
298
	if strings.HasPrefix(name, "gofile..") {
299
		name = filepath.ToSlash(name)
300
	}
301
	var align uint32
302
	if s.Func != nil {
303
		align = uint32(s.Func.Align)
304
	}
305
	if s.ContentAddressable() {
306
		// We generally assume data symbols are natually aligned,
307
		// except for strings. If we dedup a string symbol and a
308
		// non-string symbol with the same content, we should keep
309
		// the largest alignment.
310
		// TODO: maybe the compiler could set the alignment for all
311
		// data symbols more carefully.
312
		if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
313
			switch {
314
			case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
315
				align = 8
316
			case s.Size%4 == 0:
317
				align = 4
318
			case s.Size%2 == 0:
319
				align = 2
320
			}
321
			// don't bother setting align to 1.
322
		}
323
	}
324
	var o goobj.Sym
325
	o.SetName(name, w.Writer)
326
	o.SetABI(abi)
327
	o.SetType(uint8(s.Type))
328
	o.SetFlag(flag)
329
	o.SetFlag2(flag2)
330
	o.SetSiz(uint32(s.Size))
331
	o.SetAlign(align)
332
	o.Write(w.Writer)
333
}
334

335
func (w *writer) Hash64(s *LSym) {
336
	if !s.ContentAddressable() || len(s.R) != 0 {
337
		panic("Hash of non-content-addresable symbol")
338
	}
339
	b := contentHash64(s)
340
	w.Bytes(b[:])
341
}
342

343
func (w *writer) Hash(s *LSym) {
344
	if !s.ContentAddressable() {
345
		panic("Hash of non-content-addresable symbol")
346
	}
347
	b := w.contentHash(s)
348
	w.Bytes(b[:])
349
}
350

351
func contentHash64(s *LSym) goobj.Hash64Type {
352
	var b goobj.Hash64Type
353
	copy(b[:], s.P)
354
	return b
355
}
356

357
// Compute the content hash for a content-addressable symbol.
358
// We build a content hash based on its content and relocations.
359
// Depending on the category of the referenced symbol, we choose
360
// different hash algorithms such that the hash is globally
361
// consistent.
362
// - For referenced content-addressable symbol, its content hash
363
//   is globally consistent.
364
// - For package symbol and builtin symbol, its local index is
365
//   globally consistent.
366
// - For non-package symbol, its fully-expanded name is globally
367
//   consistent. For now, we require we know the current package
368
//   path so we can always expand symbol names. (Otherwise,
369
//   symbols with relocations are not considered hashable.)
370
//
371
// For now, we assume there is no circular dependencies among
372
// hashed symbols.
373
func (w *writer) contentHash(s *LSym) goobj.HashType {
374
	h := sha1.New()
375
	// The compiler trims trailing zeros _sometimes_. We just do
376
	// it always.
377
	h.Write(bytes.TrimRight(s.P, "\x00"))
378
	var tmp [14]byte
379
	for i := range s.R {
380
		r := &s.R[i]
381
		binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
382
		tmp[4] = r.Siz
383
		tmp[5] = uint8(r.Type)
384
		binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
385
		h.Write(tmp[:])
386
		rs := r.Sym
387
		switch rs.PkgIdx {
388
		case goobj.PkgIdxHashed64:
389
			h.Write([]byte{0})
390
			t := contentHash64(rs)
391
			h.Write(t[:])
392
		case goobj.PkgIdxHashed:
393
			h.Write([]byte{1})
394
			t := w.contentHash(rs)
395
			h.Write(t[:])
396
		case goobj.PkgIdxNone:
397
			h.Write([]byte{2})
398
			io.WriteString(h, rs.Name) // name is already expanded at this point
399
		case goobj.PkgIdxBuiltin:
400
			h.Write([]byte{3})
401
			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
402
			h.Write(tmp[:4])
403
		case goobj.PkgIdxSelf:
404
			io.WriteString(h, w.pkgpath)
405
			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
406
			h.Write(tmp[:4])
407
		default:
408
			io.WriteString(h, rs.Pkg)
409
			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
410
			h.Write(tmp[:4])
411
		}
412
	}
413
	var b goobj.HashType
414
	copy(b[:], h.Sum(nil))
415
	return b
416
}
417

418
func makeSymRef(s *LSym) goobj.SymRef {
419
	if s == nil {
420
		return goobj.SymRef{}
421
	}
422
	if s.PkgIdx == 0 || !s.Indexed() {
423
		fmt.Printf("unindexed symbol reference: %v\n", s)
424
		panic("unindexed symbol reference")
425
	}
426
	return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
427
}
428

429
func (w *writer) Reloc(r *Reloc) {
430
	var o goobj.Reloc
431
	o.SetOff(r.Off)
432
	o.SetSiz(r.Siz)
433
	o.SetType(uint8(r.Type))
434
	o.SetAdd(r.Add)
435
	o.SetSym(makeSymRef(r.Sym))
436
	o.Write(w.Writer)
437
}
438

439
func (w *writer) aux1(typ uint8, rs *LSym) {
440
	var o goobj.Aux
441
	o.SetType(typ)
442
	o.SetSym(makeSymRef(rs))
443
	o.Write(w.Writer)
444
}
445

446
func (w *writer) Aux(s *LSym) {
447
	if s.Gotype != nil {
448
		w.aux1(goobj.AuxGotype, s.Gotype)
449
	}
450
	if s.Func != nil {
451
		w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
452

453
		for _, d := range s.Func.Pcln.Funcdata {
454
			w.aux1(goobj.AuxFuncdata, d)
455
		}
456

457
		if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
458
			w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
459
		}
460
		if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
461
			w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
462
		}
463
		if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
464
			w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
465
		}
466
		if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
467
			w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
468
		}
469
	}
470
}
471

472
// Emits flags of referenced indexed symbols.
473
func (w *writer) refFlags() {
474
	seen := make(map[*LSym]bool)
475
	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
476
		switch rs.PkgIdx {
477
		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
478
			return
479
		case goobj.PkgIdxInvalid:
480
			panic("unindexed symbol reference")
481
		}
482
		if seen[rs] {
483
			return
484
		}
485
		seen[rs] = true
486
		symref := makeSymRef(rs)
487
		flag2 := uint8(0)
488
		if rs.UsedInIface() {
489
			flag2 |= goobj.SymFlagUsedInIface
490
		}
491
		if flag2 == 0 {
492
			return // no need to write zero flags
493
		}
494
		var o goobj.RefFlags
495
		o.SetSym(symref)
496
		o.SetFlag2(flag2)
497
		o.Write(w.Writer)
498
	})
499
}
500

501
// Emits names of referenced indexed symbols, used by tools (objdump, nm)
502
// only.
503
func (w *writer) refNames() {
504
	seen := make(map[*LSym]bool)
505
	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
506
		switch rs.PkgIdx {
507
		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
508
			return
509
		case goobj.PkgIdxInvalid:
510
			panic("unindexed symbol reference")
511
		}
512
		if seen[rs] {
513
			return
514
		}
515
		seen[rs] = true
516
		symref := makeSymRef(rs)
517
		var o goobj.RefName
518
		o.SetSym(symref)
519
		o.SetName(rs.Name, w.Writer)
520
		o.Write(w.Writer)
521
	})
522
	// TODO: output in sorted order?
523
	// Currently tools (cmd/internal/goobj package) doesn't use mmap,
524
	// and it just read it into a map in memory upfront. If it uses
525
	// mmap, if the output is sorted, it probably could avoid reading
526
	// into memory and just do lookups in the mmap'd object file.
527
}
528

529
// return the number of aux symbols s have.
530
func nAuxSym(s *LSym) int {
531
	n := 0
532
	if s.Gotype != nil {
533
		n++
534
	}
535
	if s.Func != nil {
536
		// FuncInfo is an aux symbol, each Funcdata is an aux symbol
537
		n += 1 + len(s.Func.Pcln.Funcdata)
538
		if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
539
			n++
540
		}
541
		if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
542
			n++
543
		}
544
		if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
545
			n++
546
		}
547
		if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
548
			n++
549
		}
550
	}
551
	return n
552
}
553

554
// generate symbols for FuncInfo.
555
func genFuncInfoSyms(ctxt *Link) {
556
	infosyms := make([]*LSym, 0, len(ctxt.Text))
557
	var pcdataoff uint32
558
	var b bytes.Buffer
559
	symidx := int32(len(ctxt.defs))
560
	for _, s := range ctxt.Text {
561
		if s.Func == nil {
562
			continue
563
		}
564
		o := goobj.FuncInfo{
565
			Args:   uint32(s.Func.Args),
566
			Locals: uint32(s.Func.Locals),
567
			FuncID: objabi.FuncID(s.Func.FuncID),
568
		}
569
		pc := &s.Func.Pcln
570
		o.Pcsp = pcdataoff
571
		pcdataoff += uint32(len(pc.Pcsp.P))
572
		o.Pcfile = pcdataoff
573
		pcdataoff += uint32(len(pc.Pcfile.P))
574
		o.Pcline = pcdataoff
575
		pcdataoff += uint32(len(pc.Pcline.P))
576
		o.Pcinline = pcdataoff
577
		pcdataoff += uint32(len(pc.Pcinline.P))
578
		o.Pcdata = make([]uint32, len(pc.Pcdata))
579
		for i, pcd := range pc.Pcdata {
580
			o.Pcdata[i] = pcdataoff
581
			pcdataoff += uint32(len(pcd.P))
582
		}
583
		o.PcdataEnd = pcdataoff
584
		o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
585
		for i, x := range pc.Funcdataoff {
586
			o.Funcdataoff[i] = uint32(x)
587
		}
588
		i := 0
589
		o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
590
		for f := range pc.UsedFiles {
591
			o.File[i] = f
592
			i++
593
		}
594
		sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
595
		o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
596
		for i, inl := range pc.InlTree.nodes {
597
			f, l := getFileIndexAndLine(ctxt, inl.Pos)
598
			o.InlTree[i] = goobj.InlTreeNode{
599
				Parent:   int32(inl.Parent),
600
				File:     goobj.CUFileIndex(f),
601
				Line:     l,
602
				Func:     makeSymRef(inl.Func),
603
				ParentPC: inl.ParentPC,
604
			}
605
		}
606

607
		o.Write(&b)
608
		isym := &LSym{
609
			Type:   objabi.SDATA, // for now, I don't think it matters
610
			PkgIdx: goobj.PkgIdxSelf,
611
			SymIdx: symidx,
612
			P:      append([]byte(nil), b.Bytes()...),
613
		}
614
		isym.Set(AttrIndexed, true)
615
		symidx++
616
		infosyms = append(infosyms, isym)
617
		s.Func.FuncInfoSym = isym
618
		b.Reset()
619

620
		dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
621
		for _, s := range dwsyms {
622
			if s == nil || s.Size == 0 {
623
				continue
624
			}
625
			s.PkgIdx = goobj.PkgIdxSelf
626
			s.SymIdx = symidx
627
			s.Set(AttrIndexed, true)
628
			symidx++
629
			infosyms = append(infosyms, s)
630
		}
631
	}
632
	ctxt.defs = append(ctxt.defs, infosyms...)
633
}
634

635
// debugDumpAux is a dumper for selected aux symbols.
636
func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
637
	// Most aux symbols (ex: funcdata) are not interesting--
638
	// pick out just the DWARF ones for now.
639
	if aux.Type != objabi.SDWARFLOC &&
640
		aux.Type != objabi.SDWARFFCN &&
641
		aux.Type != objabi.SDWARFABSFCN &&
642
		aux.Type != objabi.SDWARFLINES &&
643
		aux.Type != objabi.SDWARFRANGE {
644
		return
645
	}
646
	ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
647
}
648

649
func debugAsmEmit(ctxt *Link) {
650
	if ctxt.Debugasm > 0 {
651
		ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
652
		if ctxt.Debugasm > 1 {
653
			fn := func(par *LSym, aux *LSym) {
654
				writeAuxSymDebug(ctxt, par, aux)
655
			}
656
			ctxt.traverseAuxSyms(traverseAux, fn)
657
		}
658
	}
659
}
660

661
func (ctxt *Link) writeSymDebug(s *LSym) {
662
	ctxt.writeSymDebugNamed(s, s.Name)
663
}
664

665
func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
666
	ver := ""
667
	if ctxt.Debugasm > 1 {
668
		ver = fmt.Sprintf("<%d>", s.ABI())
669
	}
670
	fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
671
	if s.Type != 0 {
672
		fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
673
	}
674
	if s.Static() {
675
		fmt.Fprint(ctxt.Bso, "static ")
676
	}
677
	if s.DuplicateOK() {
678
		fmt.Fprintf(ctxt.Bso, "dupok ")
679
	}
680
	if s.CFunc() {
681
		fmt.Fprintf(ctxt.Bso, "cfunc ")
682
	}
683
	if s.NoSplit() {
684
		fmt.Fprintf(ctxt.Bso, "nosplit ")
685
	}
686
	if s.TopFrame() {
687
		fmt.Fprintf(ctxt.Bso, "topframe ")
688
	}
689
	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
690
	if s.Type == objabi.STEXT {
691
		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(s.Func.Args), uint64(s.Func.Locals), uint64(s.Func.FuncID))
692
		if s.Leaf() {
693
			fmt.Fprintf(ctxt.Bso, " leaf")
694
		}
695
	}
696
	fmt.Fprintf(ctxt.Bso, "\n")
697
	if s.Type == objabi.STEXT {
698
		for p := s.Func.Text; p != nil; p = p.Link {
699
			fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
700
			if ctxt.Debugasm > 1 {
701
				io.WriteString(ctxt.Bso, p.String())
702
			} else {
703
				p.InnermostString(ctxt.Bso)
704
			}
705
			fmt.Fprintln(ctxt.Bso)
706
		}
707
	}
708
	for i := 0; i < len(s.P); i += 16 {
709
		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
710
		j := i
711
		for ; j < i+16 && j < len(s.P); j++ {
712
			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
713
		}
714
		for ; j < i+16; j++ {
715
			fmt.Fprintf(ctxt.Bso, "   ")
716
		}
717
		fmt.Fprintf(ctxt.Bso, "  ")
718
		for j = i; j < i+16 && j < len(s.P); j++ {
719
			c := int(s.P[j])
720
			b := byte('.')
721
			if ' ' <= c && c <= 0x7e {
722
				b = byte(c)
723
			}
724
			ctxt.Bso.WriteByte(b)
725
		}
726

727
		fmt.Fprintf(ctxt.Bso, "\n")
728
	}
729

730
	sort.Sort(relocByOff(s.R)) // generate stable output
731
	for _, r := range s.R {
732
		name := ""
733
		ver := ""
734
		if r.Sym != nil {
735
			name = r.Sym.Name
736
			if ctxt.Debugasm > 1 {
737
				ver = fmt.Sprintf("<%d>", s.ABI())
738
			}
739
		} else if r.Type == objabi.R_TLS_LE {
740
			name = "TLS"
741
		}
742
		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
743
			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))
744
		} else {
745
			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
746
		}
747
	}
748
}
749

750
// relocByOff sorts relocations by their offsets.
751
type relocByOff []Reloc
752

753
func (x relocByOff) Len() int           { return len(x) }
754
func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
755
func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
756

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.