Home | History | Annotate | Download | only in 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 i := 0; i < len(pc.Pcdata); i++ {
     60 		data += len(pc.Pcdata[i].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 i := 0; i < len(pc.Pcdata); i++ {
    128 			w.wr.Write(pc.Pcdata[i].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 	if s.Static() {
    179 		w.writeInt(1)
    180 	} else {
    181 		w.writeInt(0)
    182 	}
    183 	w.nRefs++
    184 	s.RefIdx = w.nRefs
    185 	m[s.Name] = w.nRefs
    186 }
    187 
    188 func (w *objWriter) writeRefs(s *LSym) {
    189 	w.writeRef(s, false)
    190 	w.writeRef(s.Gotype, false)
    191 	for i := range s.R {
    192 		w.writeRef(s.R[i].Sym, false)
    193 	}
    194 
    195 	if s.Type == objabi.STEXT {
    196 		for _, a := range s.Func.Autom {
    197 			w.writeRef(a.Asym, false)
    198 			w.writeRef(a.Gotype, false)
    199 		}
    200 		pc := &s.Func.Pcln
    201 		for _, d := range pc.Funcdata {
    202 			w.writeRef(d, false)
    203 		}
    204 		for _, f := range pc.File {
    205 			fsym := w.ctxt.Lookup(f)
    206 			w.writeRef(fsym, true)
    207 		}
    208 		for _, call := range pc.InlTree.nodes {
    209 			w.writeRef(call.Func, false)
    210 			f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
    211 			fsym := w.ctxt.Lookup(f)
    212 			w.writeRef(fsym, true)
    213 		}
    214 	}
    215 }
    216 
    217 func (w *objWriter) writeSymDebug(s *LSym) {
    218 	ctxt := w.ctxt
    219 	fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
    220 	if s.Type != 0 {
    221 		fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
    222 	}
    223 	if s.Static() {
    224 		fmt.Fprint(ctxt.Bso, "static ")
    225 	}
    226 	if s.DuplicateOK() {
    227 		fmt.Fprintf(ctxt.Bso, "dupok ")
    228 	}
    229 	if s.CFunc() {
    230 		fmt.Fprintf(ctxt.Bso, "cfunc ")
    231 	}
    232 	if s.NoSplit() {
    233 		fmt.Fprintf(ctxt.Bso, "nosplit ")
    234 	}
    235 	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
    236 	if s.Type == objabi.STEXT {
    237 		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals))
    238 		if s.Leaf() {
    239 			fmt.Fprintf(ctxt.Bso, " leaf")
    240 		}
    241 	}
    242 	fmt.Fprintf(ctxt.Bso, "\n")
    243 	if s.Type == objabi.STEXT {
    244 		for p := s.Func.Text; p != nil; p = p.Link {
    245 			fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
    246 		}
    247 	}
    248 	for i := 0; i < len(s.P); i += 16 {
    249 		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
    250 		j := i
    251 		for j = i; j < i+16 && j < len(s.P); j++ {
    252 			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
    253 		}
    254 		for ; j < i+16; j++ {
    255 			fmt.Fprintf(ctxt.Bso, "   ")
    256 		}
    257 		fmt.Fprintf(ctxt.Bso, "  ")
    258 		for j = i; j < i+16 && j < len(s.P); j++ {
    259 			c := int(s.P[j])
    260 			if ' ' <= c && c <= 0x7e {
    261 				fmt.Fprintf(ctxt.Bso, "%c", c)
    262 			} else {
    263 				fmt.Fprintf(ctxt.Bso, ".")
    264 			}
    265 		}
    266 
    267 		fmt.Fprintf(ctxt.Bso, "\n")
    268 	}
    269 
    270 	sort.Sort(relocByOff(s.R)) // generate stable output
    271 	for _, r := range s.R {
    272 		name := ""
    273 		if r.Sym != nil {
    274 			name = r.Sym.Name
    275 		} else if r.Type == objabi.R_TLS_LE {
    276 			name = "TLS"
    277 		}
    278 		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
    279 			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
    280 		} else {
    281 			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
    282 		}
    283 	}
    284 }
    285 
    286 func (w *objWriter) writeSym(s *LSym) {
    287 	ctxt := w.ctxt
    288 	if ctxt.Debugasm {
    289 		w.writeSymDebug(s)
    290 	}
    291 
    292 	w.wr.WriteByte(symPrefix)
    293 	w.wr.WriteByte(byte(s.Type))
    294 	w.writeRefIndex(s)
    295 	flags := int64(0)
    296 	if s.DuplicateOK() {
    297 		flags |= 1
    298 	}
    299 	if s.Local() {
    300 		flags |= 1 << 1
    301 	}
    302 	if s.MakeTypelink() {
    303 		flags |= 1 << 2
    304 	}
    305 	w.writeInt(flags)
    306 	w.writeInt(s.Size)
    307 	w.writeRefIndex(s.Gotype)
    308 	w.writeInt(int64(len(s.P)))
    309 
    310 	w.writeInt(int64(len(s.R)))
    311 	var r *Reloc
    312 	for i := 0; i < len(s.R); i++ {
    313 		r = &s.R[i]
    314 		w.writeInt(int64(r.Off))
    315 		w.writeInt(int64(r.Siz))
    316 		w.writeInt(int64(r.Type))
    317 		w.writeInt(r.Add)
    318 		w.writeRefIndex(r.Sym)
    319 	}
    320 
    321 	if s.Type != objabi.STEXT {
    322 		return
    323 	}
    324 
    325 	w.writeInt(int64(s.Func.Args))
    326 	w.writeInt(int64(s.Func.Locals))
    327 	if s.NoSplit() {
    328 		w.writeInt(1)
    329 	} else {
    330 		w.writeInt(0)
    331 	}
    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 i := 0; i < len(pc.Pcdata); i++ {
    369 		w.writeInt(int64(len(pc.Pcdata[i].P)))
    370 	}
    371 	w.writeInt(int64(len(pc.Funcdataoff)))
    372 	for i := 0; i < len(pc.Funcdataoff); i++ {
    373 		w.writeRefIndex(pc.Funcdata[i])
    374 	}
    375 	for i := 0; i < len(pc.Funcdataoff); i++ {
    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 	}
    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) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
    460 	ls := s.(*LSym)
    461 	rsym := data.(*LSym)
    462 	ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
    463 }
    464 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
    465 	ls := s.(*LSym)
    466 	rsym := t.(*LSym)
    467 	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
    468 	r := &ls.R[len(ls.R)-1]
    469 	r.Type = objabi.R_DWARFSECREF
    470 }
    471 func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
    472 	ls := s.(*LSym)
    473 	rsym := f.(*LSym)
    474 	ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0)
    475 	r := &ls.R[len(ls.R)-1]
    476 	r.Type = objabi.R_DWARFFILEREF
    477 }
    478 
    479 func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
    480 	ls := s.(*LSym)
    481 	return ls.Size
    482 }
    483 
    484 // Here "from" is a symbol corresponding to an inlined or concrete
    485 // function, "to" is the symbol for the corresponding abstract
    486 // function, and "dclIdx" is the index of the symbol of interest with
    487 // respect to the Dcl slice of the original pre-optimization version
    488 // of the inlined function.
    489 func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
    490 	ls := from.(*LSym)
    491 	tls := to.(*LSym)
    492 	ridx := len(ls.R) - 1
    493 	c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
    494 }
    495 
    496 func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
    497 	ls := s.(*LSym)
    498 	c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
    499 }
    500 
    501 func (c dwCtxt) Logf(format string, args ...interface{}) {
    502 	c.Link.Logf(format, args...)
    503 }
    504 
    505 func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym *LSym) {
    506 	if s.Type != objabi.STEXT {
    507 		ctxt.Diag("dwarfSym of non-TEXT %v", s)
    508 	}
    509 	if s.Func.dwarfInfoSym == nil {
    510 		s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
    511 		if ctxt.Flag_locationlists {
    512 			s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
    513 		}
    514 		s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
    515 		if s.WasInlined() {
    516 			s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
    517 		}
    518 
    519 	}
    520 	return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym
    521 }
    522 
    523 func (s *LSym) Len() int64 {
    524 	return s.Size
    525 }
    526 
    527 // fileSymbol returns a symbol corresponding to the source file of the
    528 // first instruction (prog) of the specified function. This will
    529 // presumably be the file in which the function is defined.
    530 func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
    531 	p := fn.Func.Text
    532 	if p != nil {
    533 		f, _ := linkgetlineFromPos(ctxt, p.Pos)
    534 		fsym := ctxt.Lookup(f)
    535 		return fsym
    536 	}
    537 	return nil
    538 }
    539 
    540 // populateDWARF fills in the DWARF Debugging Information Entries for
    541 // TEXT symbol 's'. The various DWARF symbols must already have been
    542 // initialized in InitTextSym.
    543 func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
    544 	info, loc, ranges, absfunc := ctxt.dwarfSym(s)
    545 	if info.Size != 0 {
    546 		ctxt.Diag("makeFuncDebugEntry double process %v", s)
    547 	}
    548 	var scopes []dwarf.Scope
    549 	var inlcalls dwarf.InlCalls
    550 	if ctxt.DebugInfo != nil {
    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 := 0; i < len(coffsets); i++ {
    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 i := 0; i < len(sf.doffsets); i++ {
    798 			if sf.doffsets[i].dclIdx == f.dclidx {
    799 				f.refsym.R[f.relidx].Add += int64(sf.doffsets[i].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 i := 0; i < len(fns); i++ {
    852 		s := fns[i]
    853 		absfn := ft.AbsFuncDwarfSym(s)
    854 		slot, found := ft.symtab[absfn]
    855 		if !found || !ft.svec[slot].defseen {
    856 			ft.ctxt.GenAbstractFunc(s)
    857 		}
    858 	}
    859 
    860 	// Apply fixups.
    861 	for i := 0; i < len(fns); i++ {
    862 		s := fns[i]
    863 		absfn := ft.AbsFuncDwarfSym(s)
    864 		slot, found := ft.symtab[absfn]
    865 		if !found {
    866 			ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
    867 		} else {
    868 			ft.processFixups(slot, s)
    869 		}
    870 	}
    871 }
    872 
    873 type bySymName []*LSym
    874 
    875 func (s bySymName) Len() int           { return len(s) }
    876 func (s bySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
    877 func (s bySymName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    878