...
Run Format

Source file src/cmd/internal/obj/objfile.go

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

View as plain text