...

Source file src/github.com/twitchyliquid64/golang-asm/obj/objfile.go

Documentation: github.com/twitchyliquid64/golang-asm/obj

     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  

View as plain text