...

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

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

View as plain text