github.com/zxy12/go_duplicate_1_12@v0.0.0-20200217043740-b1636fc0368b/src/cmd/internal/obj/objfile.go (about)

     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 of Go object files.
     6  
     7  package obj
     8  
     9  import (
    10  	"bufio"
    11  	"cmd/internal/dwarf"
    12  	"cmd/internal/objabi"
    13  	"cmd/internal/sys"
    14  	"fmt"
    15  	"log"
    16  	"path/filepath"
    17  	"sort"
    18  	"sync"
    19  )
    20  
    21  // objWriter writes Go object files.
    22  type objWriter struct {
    23  	wr   *bufio.Writer
    24  	ctxt *Link
    25  	// Temporary buffer for zigzag int writing.
    26  	varintbuf [10]uint8
    27  
    28  	// Number of objects written of each type.
    29  	nRefs     int
    30  	nData     int
    31  	nReloc    int
    32  	nPcdata   int
    33  	nAutom    int
    34  	nFuncdata int
    35  	nFile     int
    36  }
    37  
    38  func (w *objWriter) addLengths(s *LSym) {
    39  	w.nData += len(s.P)
    40  	w.nReloc += len(s.R)
    41  
    42  	if s.Type != objabi.STEXT {
    43  		return
    44  	}
    45  
    46  	pc := &s.Func.Pcln
    47  
    48  	data := 0
    49  	data += len(pc.Pcsp.P)
    50  	data += len(pc.Pcfile.P)
    51  	data += len(pc.Pcline.P)
    52  	data += len(pc.Pcinline.P)
    53  	for _, pcd := range pc.Pcdata {
    54  		data += len(pcd.P)
    55  	}
    56  
    57  	w.nData += data
    58  	w.nPcdata += len(pc.Pcdata)
    59  
    60  	w.nAutom += len(s.Func.Autom)
    61  	w.nFuncdata += len(pc.Funcdataoff)
    62  	w.nFile += len(pc.File)
    63  }
    64  
    65  func (w *objWriter) writeLengths() {
    66  	w.writeInt(int64(w.nData))
    67  	w.writeInt(int64(w.nReloc))
    68  	w.writeInt(int64(w.nPcdata))
    69  	w.writeInt(int64(w.nAutom))
    70  	w.writeInt(int64(w.nFuncdata))
    71  	w.writeInt(int64(w.nFile))
    72  }
    73  
    74  func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
    75  	return &objWriter{
    76  		ctxt: ctxt,
    77  		wr:   b,
    78  	}
    79  }
    80  
    81  func WriteObjFile(ctxt *Link, b *bufio.Writer) {
    82  	w := newObjWriter(ctxt, b)
    83  
    84  	// Magic header
    85  	w.wr.WriteString("\x00go112ld")
    86  
    87  	// Version
    88  	w.wr.WriteByte(1)
    89  
    90  	// Autolib
    91  	for _, pkg := range ctxt.Imports {
    92  		w.writeString(pkg)
    93  	}
    94  	w.writeString("")
    95  
    96  	// Symbol references
    97  	for _, s := range ctxt.Text {
    98  		w.writeRefs(s)
    99  		w.addLengths(s)
   100  	}
   101  
   102  	if ctxt.Headtype == objabi.Haix {
   103  		// Data must be sorted to keep a constant order in TOC symbols.
   104  		// As they are created during Progedit, two symbols can be switched between
   105  		// two different compilations. Therefore, BuildID will be different.
   106  		// TODO: find a better place and optimize to only sort TOC symbols
   107  		SortSlice(ctxt.Data, func(i, j int) bool {
   108  			return ctxt.Data[i].Name < ctxt.Data[j].Name
   109  		})
   110  	}
   111  
   112  	for _, s := range ctxt.Data {
   113  		w.writeRefs(s)
   114  		w.addLengths(s)
   115  	}
   116  	for _, s := range ctxt.ABIAliases {
   117  		w.writeRefs(s)
   118  		w.addLengths(s)
   119  	}
   120  	// End symbol references
   121  	w.wr.WriteByte(0xff)
   122  
   123  	// Lengths
   124  	w.writeLengths()
   125  
   126  	// Data block
   127  	for _, s := range ctxt.Text {
   128  		w.wr.Write(s.P)
   129  		pc := &s.Func.Pcln
   130  		w.wr.Write(pc.Pcsp.P)
   131  		w.wr.Write(pc.Pcfile.P)
   132  		w.wr.Write(pc.Pcline.P)
   133  		w.wr.Write(pc.Pcinline.P)
   134  		for _, pcd := range pc.Pcdata {
   135  			w.wr.Write(pcd.P)
   136  		}
   137  	}
   138  	for _, s := range ctxt.Data {
   139  		if len(s.P) > 0 {
   140  			switch s.Type {
   141  			case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
   142  				ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name)
   143  			}
   144  		}
   145  		w.wr.Write(s.P)
   146  	}
   147  
   148  	// Symbols
   149  	for _, s := range ctxt.Text {
   150  		w.writeSym(s)
   151  	}
   152  	for _, s := range ctxt.Data {
   153  		w.writeSym(s)
   154  	}
   155  	for _, s := range ctxt.ABIAliases {
   156  		w.writeSym(s)
   157  	}
   158  
   159  	// Magic footer
   160  	w.wr.WriteString("\xffgo112ld")
   161  }
   162  
   163  // Symbols are prefixed so their content doesn't get confused with the magic footer.
   164  const symPrefix = 0xfe
   165  
   166  func (w *objWriter) writeRef(s *LSym, isPath bool) {
   167  	if s == nil || s.RefIdx != 0 {
   168  		return
   169  	}
   170  	w.wr.WriteByte(symPrefix)
   171  	if isPath {
   172  		w.writeString(filepath.ToSlash(s.Name))
   173  	} else {
   174  		w.writeString(s.Name)
   175  	}
   176  	// Write ABI/static information.
   177  	abi := int64(s.ABI())
   178  	if s.Static() {
   179  		abi = -1
   180  	}
   181  	w.writeInt(abi)
   182  	w.nRefs++
   183  	s.RefIdx = w.nRefs
   184  }
   185  
   186  func (w *objWriter) writeRefs(s *LSym) {
   187  	w.writeRef(s, false)
   188  	w.writeRef(s.Gotype, false)
   189  	for _, r := range s.R {
   190  		w.writeRef(r.Sym, false)
   191  	}
   192  
   193  	if s.Type == objabi.STEXT {
   194  		for _, a := range s.Func.Autom {
   195  			w.writeRef(a.Asym, false)
   196  			w.writeRef(a.Gotype, false)
   197  		}
   198  		pc := &s.Func.Pcln
   199  		for _, d := range pc.Funcdata {
   200  			w.writeRef(d, false)
   201  		}
   202  		for _, f := range pc.File {
   203  			fsym := w.ctxt.Lookup(f)
   204  			w.writeRef(fsym, true)
   205  		}
   206  		for _, call := range pc.InlTree.nodes {
   207  			w.writeRef(call.Func, false)
   208  			f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
   209  			fsym := w.ctxt.Lookup(f)
   210  			w.writeRef(fsym, true)
   211  		}
   212  	}
   213  }
   214  
   215  func (w *objWriter) writeSymDebug(s *LSym) {
   216  	ctxt := w.ctxt
   217  	fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
   218  	if s.Type != 0 {
   219  		fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
   220  	}
   221  	if s.Static() {
   222  		fmt.Fprint(ctxt.Bso, "static ")
   223  	}
   224  	if s.DuplicateOK() {
   225  		fmt.Fprintf(ctxt.Bso, "dupok ")
   226  	}
   227  	if s.CFunc() {
   228  		fmt.Fprintf(ctxt.Bso, "cfunc ")
   229  	}
   230  	if s.NoSplit() {
   231  		fmt.Fprintf(ctxt.Bso, "nosplit ")
   232  	}
   233  	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
   234  	if s.Type == objabi.STEXT {
   235  		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals))
   236  		if s.Leaf() {
   237  			fmt.Fprintf(ctxt.Bso, " leaf")
   238  		}
   239  	}
   240  	fmt.Fprintf(ctxt.Bso, "\n")
   241  	if s.Type == objabi.STEXT {
   242  		for p := s.Func.Text; p != nil; p = p.Link {
   243  			var s string
   244  			if ctxt.Debugasm > 1 {
   245  				s = p.String()
   246  			} else {
   247  				s = p.InnermostString()
   248  			}
   249  			fmt.Fprintf(ctxt.Bso, "\t%#04x %s\n", uint(int(p.Pc)), s)
   250  		}
   251  	}
   252  	for i := 0; i < len(s.P); i += 16 {
   253  		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
   254  		j := i
   255  		for j = i; j < i+16 && j < len(s.P); j++ {
   256  			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
   257  		}
   258  		for ; j < i+16; j++ {
   259  			fmt.Fprintf(ctxt.Bso, "   ")
   260  		}
   261  		fmt.Fprintf(ctxt.Bso, "  ")
   262  		for j = i; j < i+16 && j < len(s.P); j++ {
   263  			c := int(s.P[j])
   264  			if ' ' <= c && c <= 0x7e {
   265  				fmt.Fprintf(ctxt.Bso, "%c", c)
   266  			} else {
   267  				fmt.Fprintf(ctxt.Bso, ".")
   268  			}
   269  		}
   270  
   271  		fmt.Fprintf(ctxt.Bso, "\n")
   272  	}
   273  
   274  	sort.Sort(relocByOff(s.R)) // generate stable output
   275  	for _, r := range s.R {
   276  		name := ""
   277  		if r.Sym != nil {
   278  			name = r.Sym.Name
   279  		} else if r.Type == objabi.R_TLS_LE {
   280  			name = "TLS"
   281  		}
   282  		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
   283  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
   284  		} else {
   285  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
   286  		}
   287  	}
   288  }
   289  
   290  func (w *objWriter) writeSym(s *LSym) {
   291  	ctxt := w.ctxt
   292  	if ctxt.Debugasm > 0 {
   293  		w.writeSymDebug(s)
   294  	}
   295  
   296  	w.wr.WriteByte(symPrefix)
   297  	w.wr.WriteByte(byte(s.Type))
   298  	w.writeRefIndex(s)
   299  	flags := int64(0)
   300  	if s.DuplicateOK() {
   301  		flags |= 1
   302  	}
   303  	if s.Local() {
   304  		flags |= 1 << 1
   305  	}
   306  	if s.MakeTypelink() {
   307  		flags |= 1 << 2
   308  	}
   309  	w.writeInt(flags)
   310  	w.writeInt(s.Size)
   311  	w.writeRefIndex(s.Gotype)
   312  	w.writeInt(int64(len(s.P)))
   313  
   314  	w.writeInt(int64(len(s.R)))
   315  	var r *Reloc
   316  	for i := range s.R {
   317  		r = &s.R[i]
   318  		w.writeInt(int64(r.Off))
   319  		w.writeInt(int64(r.Siz))
   320  		w.writeInt(int64(r.Type))
   321  		w.writeInt(r.Add)
   322  		w.writeRefIndex(r.Sym)
   323  	}
   324  
   325  	if s.Type != objabi.STEXT {
   326  		return
   327  	}
   328  
   329  	w.writeInt(int64(s.Func.Args))
   330  	w.writeInt(int64(s.Func.Locals))
   331  	w.writeBool(s.NoSplit())
   332  	flags = int64(0)
   333  	if s.Leaf() {
   334  		flags |= 1
   335  	}
   336  	if s.CFunc() {
   337  		flags |= 1 << 1
   338  	}
   339  	if s.ReflectMethod() {
   340  		flags |= 1 << 2
   341  	}
   342  	if ctxt.Flag_shared {
   343  		flags |= 1 << 3
   344  	}
   345  	w.writeInt(flags)
   346  	w.writeInt(int64(len(s.Func.Autom)))
   347  	for _, a := range s.Func.Autom {
   348  		w.writeRefIndex(a.Asym)
   349  		w.writeInt(int64(a.Aoffset))
   350  		if a.Name == NAME_AUTO {
   351  			w.writeInt(objabi.A_AUTO)
   352  		} else if a.Name == NAME_PARAM {
   353  			w.writeInt(objabi.A_PARAM)
   354  		} else if a.Name == NAME_DELETED_AUTO {
   355  			w.writeInt(objabi.A_DELETED_AUTO)
   356  		} else {
   357  			log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
   358  		}
   359  		w.writeRefIndex(a.Gotype)
   360  	}
   361  
   362  	pc := &s.Func.Pcln
   363  	w.writeInt(int64(len(pc.Pcsp.P)))
   364  	w.writeInt(int64(len(pc.Pcfile.P)))
   365  	w.writeInt(int64(len(pc.Pcline.P)))
   366  	w.writeInt(int64(len(pc.Pcinline.P)))
   367  	w.writeInt(int64(len(pc.Pcdata)))
   368  	for _, pcd := range pc.Pcdata {
   369  		w.writeInt(int64(len(pcd.P)))
   370  	}
   371  	w.writeInt(int64(len(pc.Funcdataoff)))
   372  	for i := range pc.Funcdataoff {
   373  		w.writeRefIndex(pc.Funcdata[i])
   374  	}
   375  	for i := range pc.Funcdataoff {
   376  		w.writeInt(pc.Funcdataoff[i])
   377  	}
   378  	w.writeInt(int64(len(pc.File)))
   379  	for _, f := range pc.File {
   380  		fsym := ctxt.Lookup(f)
   381  		w.writeRefIndex(fsym)
   382  	}
   383  	w.writeInt(int64(len(pc.InlTree.nodes)))
   384  	for _, call := range pc.InlTree.nodes {
   385  		w.writeInt(int64(call.Parent))
   386  		f, l := linkgetlineFromPos(w.ctxt, call.Pos)
   387  		fsym := ctxt.Lookup(f)
   388  		w.writeRefIndex(fsym)
   389  		w.writeInt(int64(l))
   390  		w.writeRefIndex(call.Func)
   391  		w.writeInt(int64(call.ParentPC))
   392  	}
   393  }
   394  
   395  func (w *objWriter) writeBool(b bool) {
   396  	if b {
   397  		w.writeInt(1)
   398  	} else {
   399  		w.writeInt(0)
   400  	}
   401  }
   402  
   403  func (w *objWriter) writeInt(sval int64) {
   404  	var v uint64
   405  	uv := (uint64(sval) << 1) ^ uint64(sval>>63)
   406  	p := w.varintbuf[:]
   407  	for v = uv; v >= 0x80; v >>= 7 {
   408  		p[0] = uint8(v | 0x80)
   409  		p = p[1:]
   410  	}
   411  	p[0] = uint8(v)
   412  	p = p[1:]
   413  	w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
   414  }
   415  
   416  func (w *objWriter) writeString(s string) {
   417  	w.writeInt(int64(len(s)))
   418  	w.wr.WriteString(s)
   419  }
   420  
   421  func (w *objWriter) writeRefIndex(s *LSym) {
   422  	if s == nil {
   423  		w.writeInt(0)
   424  		return
   425  	}
   426  	if s.RefIdx == 0 {
   427  		log.Fatalln("writing an unreferenced symbol", s.Name)
   428  	}
   429  	w.writeInt(int64(s.RefIdx))
   430  }
   431  
   432  // relocByOff sorts relocations by their offsets.
   433  type relocByOff []Reloc
   434  
   435  func (x relocByOff) Len() int           { return len(x) }
   436  func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
   437  func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   438  
   439  // implement dwarf.Context
   440  type dwCtxt struct{ *Link }
   441  
   442  func (c dwCtxt) PtrSize() int {
   443  	return c.Arch.PtrSize
   444  }
   445  func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
   446  	ls := s.(*LSym)
   447  	ls.WriteInt(c.Link, ls.Size, size, i)
   448  }
   449  func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
   450  	ls := s.(*LSym)
   451  	ls.WriteBytes(c.Link, ls.Size, b)
   452  }
   453  func (c dwCtxt) AddString(s dwarf.Sym, v string) {
   454  	ls := s.(*LSym)
   455  	ls.WriteString(c.Link, ls.Size, len(v), v)
   456  	ls.WriteInt(c.Link, ls.Size, 1, 0)
   457  }
   458  func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
   459  	ls := s.(*LSym)
   460  	size := c.PtrSize()
   461  	if data != nil {
   462  		rsym := data.(*LSym)
   463  		ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
   464  	} else {
   465  		ls.WriteInt(c.Link, ls.Size, size, value)
   466  	}
   467  }
   468  func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
   469  	panic("should be used only in the linker")
   470  }
   471  func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
   472  	size := 4
   473  	if isDwarf64(c.Link) {
   474  		size = 8
   475  	}
   476  
   477  	ls := s.(*LSym)
   478  	rsym := t.(*LSym)
   479  	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
   480  	r := &ls.R[len(ls.R)-1]
   481  	r.Type = objabi.R_DWARFSECREF
   482  }
   483  func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
   484  	ls := s.(*LSym)
   485  	rsym := f.(*LSym)
   486  	ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0)
   487  	r := &ls.R[len(ls.R)-1]
   488  	r.Type = objabi.R_DWARFFILEREF
   489  }
   490  
   491  func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
   492  	ls := s.(*LSym)
   493  	return ls.Size
   494  }
   495  
   496  // Here "from" is a symbol corresponding to an inlined or concrete
   497  // function, "to" is the symbol for the corresponding abstract
   498  // function, and "dclIdx" is the index of the symbol of interest with
   499  // respect to the Dcl slice of the original pre-optimization version
   500  // of the inlined function.
   501  func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
   502  	ls := from.(*LSym)
   503  	tls := to.(*LSym)
   504  	ridx := len(ls.R) - 1
   505  	c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
   506  }
   507  
   508  func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
   509  	ls := s.(*LSym)
   510  	c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
   511  }
   512  
   513  func (c dwCtxt) Logf(format string, args ...interface{}) {
   514  	c.Link.Logf(format, args...)
   515  }
   516  
   517  func isDwarf64(ctxt *Link) bool {
   518  	return ctxt.Headtype == objabi.Haix
   519  }
   520  
   521  func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfIsStmtSym *LSym) {
   522  	if s.Type != objabi.STEXT {
   523  		ctxt.Diag("dwarfSym of non-TEXT %v", s)
   524  	}
   525  	if s.Func.dwarfInfoSym == nil {
   526  		s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
   527  		if ctxt.Flag_locationlists {
   528  			s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
   529  		}
   530  		s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
   531  		if s.WasInlined() {
   532  			s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
   533  		}
   534  		s.Func.dwarfIsStmtSym = ctxt.LookupDerived(s, dwarf.IsStmtPrefix+s.Name)
   535  
   536  	}
   537  	return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfIsStmtSym
   538  }
   539  
   540  func (s *LSym) Len() int64 {
   541  	return s.Size
   542  }
   543  
   544  // fileSymbol returns a symbol corresponding to the source file of the
   545  // first instruction (prog) of the specified function. This will
   546  // presumably be the file in which the function is defined.
   547  func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
   548  	p := fn.Func.Text
   549  	if p != nil {
   550  		f, _ := linkgetlineFromPos(ctxt, p.Pos)
   551  		fsym := ctxt.Lookup(f)
   552  		return fsym
   553  	}
   554  	return nil
   555  }
   556  
   557  // populateDWARF fills in the DWARF Debugging Information Entries for
   558  // TEXT symbol 's'. The various DWARF symbols must already have been
   559  // initialized in InitTextSym.
   560  func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
   561  	info, loc, ranges, absfunc, _ := ctxt.dwarfSym(s)
   562  	if info.Size != 0 {
   563  		ctxt.Diag("makeFuncDebugEntry double process %v", s)
   564  	}
   565  	var scopes []dwarf.Scope
   566  	var inlcalls dwarf.InlCalls
   567  	if ctxt.DebugInfo != nil {
   568  		stmtData(ctxt, s)
   569  		scopes, inlcalls = ctxt.DebugInfo(s, curfn)
   570  	}
   571  	var err error
   572  	dwctxt := dwCtxt{ctxt}
   573  	filesym := ctxt.fileSymbol(s)
   574  	fnstate := &dwarf.FnState{
   575  		Name:       s.Name,
   576  		Importpath: myimportpath,
   577  		Info:       info,
   578  		Filesym:    filesym,
   579  		Loc:        loc,
   580  		Ranges:     ranges,
   581  		Absfn:      absfunc,
   582  		StartPC:    s,
   583  		Size:       s.Size,
   584  		External:   !s.Static(),
   585  		Scopes:     scopes,
   586  		InlCalls:   inlcalls,
   587  	}
   588  	if absfunc != nil {
   589  		err = dwarf.PutAbstractFunc(dwctxt, fnstate)
   590  		if err != nil {
   591  			ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
   592  		}
   593  		err = dwarf.PutConcreteFunc(dwctxt, fnstate)
   594  	} else {
   595  		err = dwarf.PutDefaultFunc(dwctxt, fnstate)
   596  	}
   597  	if err != nil {
   598  		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
   599  	}
   600  }
   601  
   602  // DwarfIntConst creates a link symbol for an integer constant with the
   603  // given name, type and value.
   604  func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
   605  	if myimportpath == "" {
   606  		return
   607  	}
   608  	s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
   609  		s.Type = objabi.SDWARFINFO
   610  		ctxt.Data = append(ctxt.Data, s)
   611  	})
   612  	dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
   613  }
   614  
   615  func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
   616  	absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
   617  	if absfn.Size != 0 {
   618  		ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
   619  	}
   620  	if s.Func == nil {
   621  		s.Func = new(FuncInfo)
   622  	}
   623  	scopes, _ := ctxt.DebugInfo(s, curfn)
   624  	dwctxt := dwCtxt{ctxt}
   625  	filesym := ctxt.fileSymbol(s)
   626  	fnstate := dwarf.FnState{
   627  		Name:       s.Name,
   628  		Importpath: myimportpath,
   629  		Info:       absfn,
   630  		Filesym:    filesym,
   631  		Absfn:      absfn,
   632  		External:   !s.Static(),
   633  		Scopes:     scopes,
   634  	}
   635  	if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
   636  		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
   637  	}
   638  }
   639  
   640  // This table is designed to aid in the creation of references betweeen
   641  // DWARF subprogram DIEs.
   642  //
   643  // In most cases when one DWARF DIE has to refer to another DWARF DIE,
   644  // the target of the reference has an LSym, which makes it easy to use
   645  // the existing relocation mechanism. For DWARF inlined routine DIEs,
   646  // however, the subprogram DIE has to refer to a child
   647  // parameter/variable DIE of the abstract subprogram. This child DIE
   648  // doesn't have an LSym, and also of interest is the fact that when
   649  // DWARF generation is happening for inlined function F within caller
   650  // G, it's possible that DWARF generation hasn't happened yet for F,
   651  // so there is no way to know the offset of a child DIE within F's
   652  // abstract function. Making matters more complex, each inlined
   653  // instance of F may refer to a subset of the original F's variables
   654  // (depending on what happens with optimization, some vars may be
   655  // eliminated).
   656  //
   657  // The fixup table below helps overcome this hurdle. At the point
   658  // where a parameter/variable reference is made (via a call to
   659  // "ReferenceChildDIE"), a fixup record is generate that records
   660  // the relocation that is targeting that child variable. At a later
   661  // point when the abstract function DIE is emitted, there will be
   662  // a call to "RegisterChildDIEOffsets", at which point the offsets
   663  // needed to apply fixups are captured. Finally, once the parallel
   664  // portion of the compilation is done, fixups can actually be applied
   665  // during the "Finalize" method (this can't be done during the
   666  // parallel portion of the compile due to the possibility of data
   667  // races).
   668  //
   669  // This table is also used to record the "precursor" function node for
   670  // each function that is the target of an inline -- child DIE references
   671  // have to be made with respect to the original pre-optimization
   672  // version of the function (to allow for the fact that each inlined
   673  // body may be optimized differently).
   674  type DwarfFixupTable struct {
   675  	ctxt      *Link
   676  	mu        sync.Mutex
   677  	symtab    map[*LSym]int // maps abstract fn LSYM to index in svec
   678  	svec      []symFixups
   679  	precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
   680  }
   681  
   682  type symFixups struct {
   683  	fixups   []relFixup
   684  	doffsets []declOffset
   685  	inlIndex int32
   686  	defseen  bool
   687  }
   688  
   689  type declOffset struct {
   690  	// Index of variable within DCL list of pre-optimization function
   691  	dclIdx int32
   692  	// Offset of var's child DIE with respect to containing subprogram DIE
   693  	offset int32
   694  }
   695  
   696  type relFixup struct {
   697  	refsym *LSym
   698  	relidx int32
   699  	dclidx int32
   700  }
   701  
   702  type fnState struct {
   703  	// precursor function (really *gc.Node)
   704  	precursor interface{}
   705  	// abstract function symbol
   706  	absfn *LSym
   707  }
   708  
   709  func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
   710  	return &DwarfFixupTable{
   711  		ctxt:      ctxt,
   712  		symtab:    make(map[*LSym]int),
   713  		precursor: make(map[*LSym]fnState),
   714  	}
   715  }
   716  
   717  func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
   718  	if fnstate, found := ft.precursor[s]; found {
   719  		return fnstate.precursor
   720  	}
   721  	return nil
   722  }
   723  
   724  func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
   725  	if _, found := ft.precursor[s]; found {
   726  		ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
   727  	}
   728  
   729  	// initialize abstract function symbol now. This is done here so
   730  	// as to avoid data races later on during the parallel portion of
   731  	// the back end.
   732  	absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
   733  	absfn.Set(AttrDuplicateOK, true)
   734  	absfn.Type = objabi.SDWARFINFO
   735  	ft.ctxt.Data = append(ft.ctxt.Data, absfn)
   736  
   737  	ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
   738  }
   739  
   740  // Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
   741  // is targeting child 'c' of DIE with symbol 'tgt'.
   742  func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
   743  	// Protect against concurrent access if multiple backend workers
   744  	ft.mu.Lock()
   745  	defer ft.mu.Unlock()
   746  
   747  	// Create entry for symbol if not already present.
   748  	idx, found := ft.symtab[tgt]
   749  	if !found {
   750  		ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
   751  		idx = len(ft.svec) - 1
   752  		ft.symtab[tgt] = idx
   753  	}
   754  
   755  	// Do we have child DIE offsets available? If so, then apply them,
   756  	// otherwise create a fixup record.
   757  	sf := &ft.svec[idx]
   758  	if len(sf.doffsets) > 0 {
   759  		found := false
   760  		for _, do := range sf.doffsets {
   761  			if do.dclIdx == int32(dclidx) {
   762  				off := do.offset
   763  				s.R[ridx].Add += int64(off)
   764  				found = true
   765  				break
   766  			}
   767  		}
   768  		if !found {
   769  			ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
   770  		}
   771  	} else {
   772  		sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
   773  	}
   774  }
   775  
   776  // Called once DWARF generation is complete for a given abstract function,
   777  // whose children might have been referenced via a call above. Stores
   778  // the offsets for any child DIEs (vars, params) so that they can be
   779  // consumed later in on DwarfFixupTable.Finalize, which applies any
   780  // outstanding fixups.
   781  func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
   782  	// Length of these two slices should agree
   783  	if len(vars) != len(coffsets) {
   784  		ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
   785  		return
   786  	}
   787  
   788  	// Generate the slice of declOffset's based in vars/coffsets
   789  	doffsets := make([]declOffset, len(coffsets))
   790  	for i := range coffsets {
   791  		doffsets[i].dclIdx = vars[i].ChildIndex
   792  		doffsets[i].offset = coffsets[i]
   793  	}
   794  
   795  	ft.mu.Lock()
   796  	defer ft.mu.Unlock()
   797  
   798  	// Store offsets for this symbol.
   799  	idx, found := ft.symtab[s]
   800  	if !found {
   801  		sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
   802  		ft.svec = append(ft.svec, sf)
   803  		ft.symtab[s] = len(ft.svec) - 1
   804  	} else {
   805  		sf := &ft.svec[idx]
   806  		sf.doffsets = doffsets
   807  		sf.defseen = true
   808  	}
   809  }
   810  
   811  func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
   812  	sf := &ft.svec[slot]
   813  	for _, f := range sf.fixups {
   814  		dfound := false
   815  		for _, doffset := range sf.doffsets {
   816  			if doffset.dclIdx == f.dclidx {
   817  				f.refsym.R[f.relidx].Add += int64(doffset.offset)
   818  				dfound = true
   819  				break
   820  			}
   821  		}
   822  		if !dfound {
   823  			ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
   824  		}
   825  	}
   826  }
   827  
   828  // return the LSym corresponding to the 'abstract subprogram' DWARF
   829  // info entry for a function.
   830  func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
   831  	// Protect against concurrent access if multiple backend workers
   832  	ft.mu.Lock()
   833  	defer ft.mu.Unlock()
   834  
   835  	if fnstate, found := ft.precursor[fnsym]; found {
   836  		return fnstate.absfn
   837  	}
   838  	ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
   839  	return nil
   840  }
   841  
   842  // Called after all functions have been compiled; the main job of this
   843  // function is to identify cases where there are outstanding fixups.
   844  // This scenario crops up when we have references to variables of an
   845  // inlined routine, but that routine is defined in some other package.
   846  // This helper walks through and locate these fixups, then invokes a
   847  // helper to create an abstract subprogram DIE for each one.
   848  func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
   849  	if trace {
   850  		ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
   851  	}
   852  
   853  	// Collect up the keys from the precursor map, then sort the
   854  	// resulting list (don't want to rely on map ordering here).
   855  	fns := make([]*LSym, len(ft.precursor))
   856  	idx := 0
   857  	for fn := range ft.precursor {
   858  		fns[idx] = fn
   859  		idx++
   860  	}
   861  	sort.Sort(bySymName(fns))
   862  
   863  	// Should not be called during parallel portion of compilation.
   864  	if ft.ctxt.InParallel {
   865  		ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
   866  	}
   867  
   868  	// Generate any missing abstract functions.
   869  	for _, s := range fns {
   870  		absfn := ft.AbsFuncDwarfSym(s)
   871  		slot, found := ft.symtab[absfn]
   872  		if !found || !ft.svec[slot].defseen {
   873  			ft.ctxt.GenAbstractFunc(s)
   874  		}
   875  	}
   876  
   877  	// Apply fixups.
   878  	for _, s := range fns {
   879  		absfn := ft.AbsFuncDwarfSym(s)
   880  		slot, found := ft.symtab[absfn]
   881  		if !found {
   882  			ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
   883  		} else {
   884  			ft.processFixups(slot, s)
   885  		}
   886  	}
   887  }
   888  
   889  type bySymName []*LSym
   890  
   891  func (s bySymName) Len() int           { return len(s) }
   892  func (s bySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
   893  func (s bySymName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }