[dev.link] cmd/internal/obj: combine objfile.go and objfile2.go

Combine objfile2.go into objfile.go.

objfile.go has a lot of code for DWARF generation. Move them to
dwarf.go.

Change-Id: I2a27c672e9e9b8eea35d5e0a71433dcc80b7afa4
Reviewed-on: https://go-review.googlesource.com/c/go/+/247918
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/src/cmd/internal/obj/dwarf.go b/src/cmd/internal/obj/dwarf.go
index 724aea2..9abb31b 100644
--- a/src/cmd/internal/obj/dwarf.go
+++ b/src/cmd/internal/obj/dwarf.go
@@ -8,8 +8,11 @@
 
 import (
 	"cmd/internal/dwarf"
+	"cmd/internal/objabi"
 	"cmd/internal/src"
 	"fmt"
+	"sort"
+	"sync"
 )
 
 // Generate a sequence of opcodes that is as short as possible.
@@ -196,3 +199,492 @@
 	// Output the special opcode.
 	dctxt.AddUint8(s, uint8(opcode))
 }
+
+// implement dwarf.Context
+type dwCtxt struct{ *Link }
+
+func (c dwCtxt) PtrSize() int {
+	return c.Arch.PtrSize
+}
+func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
+	ls := s.(*LSym)
+	ls.WriteInt(c.Link, ls.Size, size, i)
+}
+func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
+	c.AddInt(s, 2, int64(i))
+}
+func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
+	b := []byte{byte(i)}
+	c.AddBytes(s, b)
+}
+func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
+	ls := s.(*LSym)
+	ls.WriteBytes(c.Link, ls.Size, b)
+}
+func (c dwCtxt) AddString(s dwarf.Sym, v string) {
+	ls := s.(*LSym)
+	ls.WriteString(c.Link, ls.Size, len(v), v)
+	ls.WriteInt(c.Link, ls.Size, 1, 0)
+}
+func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
+	ls := s.(*LSym)
+	size := c.PtrSize()
+	if data != nil {
+		rsym := data.(*LSym)
+		ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
+	} else {
+		ls.WriteInt(c.Link, ls.Size, size, value)
+	}
+}
+func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
+	ls := s.(*LSym)
+	rsym := data.(*LSym)
+	ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
+}
+func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
+	panic("should be used only in the linker")
+}
+func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
+	size := 4
+	if isDwarf64(c.Link) {
+		size = 8
+	}
+
+	ls := s.(*LSym)
+	rsym := t.(*LSym)
+	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
+	r := &ls.R[len(ls.R)-1]
+	r.Type = objabi.R_DWARFSECREF
+}
+
+func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
+	ls := s.(*LSym)
+	rsym := f.(*LSym)
+	fidx := c.Link.PosTable.FileIndex(rsym.Name)
+	// Note the +1 here -- the value we're writing is going to be an
+	// index into the DWARF line table file section, whose entries
+	// are numbered starting at 1, not 0.
+	ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
+}
+
+func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
+	ls := s.(*LSym)
+	return ls.Size
+}
+
+// Here "from" is a symbol corresponding to an inlined or concrete
+// function, "to" is the symbol for the corresponding abstract
+// function, and "dclIdx" is the index of the symbol of interest with
+// respect to the Dcl slice of the original pre-optimization version
+// of the inlined function.
+func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
+	ls := from.(*LSym)
+	tls := to.(*LSym)
+	ridx := len(ls.R) - 1
+	c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
+}
+
+func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
+	ls := s.(*LSym)
+	c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
+}
+
+func (c dwCtxt) Logf(format string, args ...interface{}) {
+	c.Link.Logf(format, args...)
+}
+
+func isDwarf64(ctxt *Link) bool {
+	return ctxt.Headtype == objabi.Haix
+}
+
+func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
+	if s.Type != objabi.STEXT {
+		ctxt.Diag("dwarfSym of non-TEXT %v", s)
+	}
+	if s.Func.dwarfInfoSym == nil {
+		s.Func.dwarfInfoSym = &LSym{
+			Type: objabi.SDWARFFCN,
+		}
+		if ctxt.Flag_locationlists {
+			s.Func.dwarfLocSym = &LSym{
+				Type: objabi.SDWARFLOC,
+			}
+		}
+		s.Func.dwarfRangesSym = &LSym{
+			Type: objabi.SDWARFRANGE,
+		}
+		s.Func.dwarfDebugLinesSym = &LSym{
+			Type: objabi.SDWARFLINES,
+		}
+		if s.WasInlined() {
+			s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
+		}
+	}
+	return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
+}
+
+func (s *LSym) Length(dwarfContext interface{}) int64 {
+	return s.Size
+}
+
+// fileSymbol returns a symbol corresponding to the source file of the
+// first instruction (prog) of the specified function. This will
+// presumably be the file in which the function is defined.
+func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
+	p := fn.Func.Text
+	if p != nil {
+		f, _ := linkgetlineFromPos(ctxt, p.Pos)
+		fsym := ctxt.Lookup(f)
+		return fsym
+	}
+	return nil
+}
+
+// populateDWARF fills in the DWARF Debugging Information Entries for
+// TEXT symbol 's'. The various DWARF symbols must already have been
+// initialized in InitTextSym.
+func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
+	info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
+	if info.Size != 0 {
+		ctxt.Diag("makeFuncDebugEntry double process %v", s)
+	}
+	var scopes []dwarf.Scope
+	var inlcalls dwarf.InlCalls
+	if ctxt.DebugInfo != nil {
+		scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
+	}
+	var err error
+	dwctxt := dwCtxt{ctxt}
+	filesym := ctxt.fileSymbol(s)
+	fnstate := &dwarf.FnState{
+		Name:          s.Name,
+		Importpath:    myimportpath,
+		Info:          info,
+		Filesym:       filesym,
+		Loc:           loc,
+		Ranges:        ranges,
+		Absfn:         absfunc,
+		StartPC:       s,
+		Size:          s.Size,
+		External:      !s.Static(),
+		Scopes:        scopes,
+		InlCalls:      inlcalls,
+		UseBASEntries: ctxt.UseBASEntries,
+	}
+	if absfunc != nil {
+		err = dwarf.PutAbstractFunc(dwctxt, fnstate)
+		if err != nil {
+			ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
+		}
+		err = dwarf.PutConcreteFunc(dwctxt, fnstate)
+	} else {
+		err = dwarf.PutDefaultFunc(dwctxt, fnstate)
+	}
+	if err != nil {
+		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
+	}
+	// Fill in the debug lines symbol.
+	ctxt.generateDebugLinesSymbol(s, lines)
+}
+
+// DwarfIntConst creates a link symbol for an integer constant with the
+// given name, type and value.
+func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
+	if myimportpath == "" {
+		return
+	}
+	s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
+		s.Type = objabi.SDWARFCONST
+		ctxt.Data = append(ctxt.Data, s)
+	})
+	dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
+}
+
+func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
+	absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
+	if absfn.Size != 0 {
+		ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
+	}
+	if s.Func == nil {
+		s.Func = new(FuncInfo)
+	}
+	scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
+	dwctxt := dwCtxt{ctxt}
+	filesym := ctxt.fileSymbol(s)
+	fnstate := dwarf.FnState{
+		Name:          s.Name,
+		Importpath:    myimportpath,
+		Info:          absfn,
+		Filesym:       filesym,
+		Absfn:         absfn,
+		External:      !s.Static(),
+		Scopes:        scopes,
+		UseBASEntries: ctxt.UseBASEntries,
+	}
+	if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
+		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
+	}
+}
+
+// This table is designed to aid in the creation of references between
+// DWARF subprogram DIEs.
+//
+// In most cases when one DWARF DIE has to refer to another DWARF DIE,
+// the target of the reference has an LSym, which makes it easy to use
+// the existing relocation mechanism. For DWARF inlined routine DIEs,
+// however, the subprogram DIE has to refer to a child
+// parameter/variable DIE of the abstract subprogram. This child DIE
+// doesn't have an LSym, and also of interest is the fact that when
+// DWARF generation is happening for inlined function F within caller
+// G, it's possible that DWARF generation hasn't happened yet for F,
+// so there is no way to know the offset of a child DIE within F's
+// abstract function. Making matters more complex, each inlined
+// instance of F may refer to a subset of the original F's variables
+// (depending on what happens with optimization, some vars may be
+// eliminated).
+//
+// The fixup table below helps overcome this hurdle. At the point
+// where a parameter/variable reference is made (via a call to
+// "ReferenceChildDIE"), a fixup record is generate that records
+// the relocation that is targeting that child variable. At a later
+// point when the abstract function DIE is emitted, there will be
+// a call to "RegisterChildDIEOffsets", at which point the offsets
+// needed to apply fixups are captured. Finally, once the parallel
+// portion of the compilation is done, fixups can actually be applied
+// during the "Finalize" method (this can't be done during the
+// parallel portion of the compile due to the possibility of data
+// races).
+//
+// This table is also used to record the "precursor" function node for
+// each function that is the target of an inline -- child DIE references
+// have to be made with respect to the original pre-optimization
+// version of the function (to allow for the fact that each inlined
+// body may be optimized differently).
+type DwarfFixupTable struct {
+	ctxt      *Link
+	mu        sync.Mutex
+	symtab    map[*LSym]int // maps abstract fn LSYM to index in svec
+	svec      []symFixups
+	precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
+}
+
+type symFixups struct {
+	fixups   []relFixup
+	doffsets []declOffset
+	inlIndex int32
+	defseen  bool
+}
+
+type declOffset struct {
+	// Index of variable within DCL list of pre-optimization function
+	dclIdx int32
+	// Offset of var's child DIE with respect to containing subprogram DIE
+	offset int32
+}
+
+type relFixup struct {
+	refsym *LSym
+	relidx int32
+	dclidx int32
+}
+
+type fnState struct {
+	// precursor function (really *gc.Node)
+	precursor interface{}
+	// abstract function symbol
+	absfn *LSym
+}
+
+func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
+	return &DwarfFixupTable{
+		ctxt:      ctxt,
+		symtab:    make(map[*LSym]int),
+		precursor: make(map[*LSym]fnState),
+	}
+}
+
+func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
+	if fnstate, found := ft.precursor[s]; found {
+		return fnstate.precursor
+	}
+	return nil
+}
+
+func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
+	if _, found := ft.precursor[s]; found {
+		ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
+	}
+
+	// initialize abstract function symbol now. This is done here so
+	// as to avoid data races later on during the parallel portion of
+	// the back end.
+	absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
+	absfn.Set(AttrDuplicateOK, true)
+	absfn.Type = objabi.SDWARFABSFCN
+	ft.ctxt.Data = append(ft.ctxt.Data, absfn)
+
+	// In the case of "late" inlining (inlines that happen during
+	// wrapper generation as opposed to the main inlining phase) it's
+	// possible that we didn't cache the abstract function sym for the
+	// text symbol -- do so now if needed. See issue 38068.
+	if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
+		s.Func.dwarfAbsFnSym = absfn
+	}
+
+	ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
+}
+
+// Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
+// is targeting child 'c' of DIE with symbol 'tgt'.
+func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
+	// Protect against concurrent access if multiple backend workers
+	ft.mu.Lock()
+	defer ft.mu.Unlock()
+
+	// Create entry for symbol if not already present.
+	idx, found := ft.symtab[tgt]
+	if !found {
+		ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
+		idx = len(ft.svec) - 1
+		ft.symtab[tgt] = idx
+	}
+
+	// Do we have child DIE offsets available? If so, then apply them,
+	// otherwise create a fixup record.
+	sf := &ft.svec[idx]
+	if len(sf.doffsets) > 0 {
+		found := false
+		for _, do := range sf.doffsets {
+			if do.dclIdx == int32(dclidx) {
+				off := do.offset
+				s.R[ridx].Add += int64(off)
+				found = true
+				break
+			}
+		}
+		if !found {
+			ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
+		}
+	} else {
+		sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
+	}
+}
+
+// Called once DWARF generation is complete for a given abstract function,
+// whose children might have been referenced via a call above. Stores
+// the offsets for any child DIEs (vars, params) so that they can be
+// consumed later in on DwarfFixupTable.Finalize, which applies any
+// outstanding fixups.
+func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
+	// Length of these two slices should agree
+	if len(vars) != len(coffsets) {
+		ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
+		return
+	}
+
+	// Generate the slice of declOffset's based in vars/coffsets
+	doffsets := make([]declOffset, len(coffsets))
+	for i := range coffsets {
+		doffsets[i].dclIdx = vars[i].ChildIndex
+		doffsets[i].offset = coffsets[i]
+	}
+
+	ft.mu.Lock()
+	defer ft.mu.Unlock()
+
+	// Store offsets for this symbol.
+	idx, found := ft.symtab[s]
+	if !found {
+		sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
+		ft.svec = append(ft.svec, sf)
+		ft.symtab[s] = len(ft.svec) - 1
+	} else {
+		sf := &ft.svec[idx]
+		sf.doffsets = doffsets
+		sf.defseen = true
+	}
+}
+
+func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
+	sf := &ft.svec[slot]
+	for _, f := range sf.fixups {
+		dfound := false
+		for _, doffset := range sf.doffsets {
+			if doffset.dclIdx == f.dclidx {
+				f.refsym.R[f.relidx].Add += int64(doffset.offset)
+				dfound = true
+				break
+			}
+		}
+		if !dfound {
+			ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
+		}
+	}
+}
+
+// return the LSym corresponding to the 'abstract subprogram' DWARF
+// info entry for a function.
+func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
+	// Protect against concurrent access if multiple backend workers
+	ft.mu.Lock()
+	defer ft.mu.Unlock()
+
+	if fnstate, found := ft.precursor[fnsym]; found {
+		return fnstate.absfn
+	}
+	ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
+	return nil
+}
+
+// Called after all functions have been compiled; the main job of this
+// function is to identify cases where there are outstanding fixups.
+// This scenario crops up when we have references to variables of an
+// inlined routine, but that routine is defined in some other package.
+// This helper walks through and locate these fixups, then invokes a
+// helper to create an abstract subprogram DIE for each one.
+func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
+	if trace {
+		ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
+	}
+
+	// Collect up the keys from the precursor map, then sort the
+	// resulting list (don't want to rely on map ordering here).
+	fns := make([]*LSym, len(ft.precursor))
+	idx := 0
+	for fn := range ft.precursor {
+		fns[idx] = fn
+		idx++
+	}
+	sort.Sort(BySymName(fns))
+
+	// Should not be called during parallel portion of compilation.
+	if ft.ctxt.InParallel {
+		ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
+	}
+
+	// Generate any missing abstract functions.
+	for _, s := range fns {
+		absfn := ft.AbsFuncDwarfSym(s)
+		slot, found := ft.symtab[absfn]
+		if !found || !ft.svec[slot].defseen {
+			ft.ctxt.GenAbstractFunc(s)
+		}
+	}
+
+	// Apply fixups.
+	for _, s := range fns {
+		absfn := ft.AbsFuncDwarfSym(s)
+		slot, found := ft.symtab[absfn]
+		if !found {
+			ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
+		} else {
+			ft.processFixups(slot, s)
+		}
+	}
+}
+
+type BySymName []*LSym
+
+func (s BySymName) Len() int           { return len(s) }
+func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
+func (s BySymName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 2f28b6e..7bc4f49 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -2,18 +2,662 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Writing Go object files.
+
 package obj
 
 import (
-	"cmd/internal/dwarf"
+	"bytes"
+	"cmd/internal/bio"
+	"cmd/internal/goobj"
 	"cmd/internal/objabi"
 	"cmd/internal/sys"
+	"crypto/sha1"
+	"encoding/binary"
 	"fmt"
 	"io"
+	"path/filepath"
 	"sort"
-	"sync"
+	"strings"
 )
 
+// Entry point of writing new object file.
+func WriteObjFile(ctxt *Link, b *bio.Writer) {
+
+	debugAsmEmit(ctxt)
+
+	genFuncInfoSyms(ctxt)
+
+	w := writer{
+		Writer:  goobj.NewWriter(b),
+		ctxt:    ctxt,
+		pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
+	}
+
+	start := b.Offset()
+	w.init()
+
+	// Header
+	// We just reserve the space. We'll fill in the offsets later.
+	flags := uint32(0)
+	if ctxt.Flag_shared {
+		flags |= goobj.ObjFlagShared
+	}
+	if w.pkgpath == "" {
+		flags |= goobj.ObjFlagNeedNameExpansion
+	}
+	if ctxt.IsAsm {
+		flags |= goobj.ObjFlagFromAssembly
+	}
+	h := goobj.Header{
+		Magic:       goobj.Magic,
+		Fingerprint: ctxt.Fingerprint,
+		Flags:       flags,
+	}
+	h.Write(w.Writer)
+
+	// String table
+	w.StringTable()
+
+	// Autolib
+	h.Offsets[goobj.BlkAutolib] = w.Offset()
+	for i := range ctxt.Imports {
+		ctxt.Imports[i].Write(w.Writer)
+	}
+
+	// Package references
+	h.Offsets[goobj.BlkPkgIdx] = w.Offset()
+	for _, pkg := range w.pkglist {
+		w.StringRef(pkg)
+	}
+
+	// File table (for DWARF and pcln generation).
+	h.Offsets[goobj.BlkFile] = w.Offset()
+	for _, f := range ctxt.PosTable.FileTable() {
+		w.StringRef(filepath.ToSlash(f))
+	}
+
+	// Symbol definitions
+	h.Offsets[goobj.BlkSymdef] = w.Offset()
+	for _, s := range ctxt.defs {
+		w.Sym(s)
+	}
+
+	// Short hashed symbol definitions
+	h.Offsets[goobj.BlkHashed64def] = w.Offset()
+	for _, s := range ctxt.hashed64defs {
+		w.Sym(s)
+	}
+
+	// Hashed symbol definitions
+	h.Offsets[goobj.BlkHasheddef] = w.Offset()
+	for _, s := range ctxt.hasheddefs {
+		w.Sym(s)
+	}
+
+	// Non-pkg symbol definitions
+	h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
+	for _, s := range ctxt.nonpkgdefs {
+		w.Sym(s)
+	}
+
+	// Non-pkg symbol references
+	h.Offsets[goobj.BlkNonpkgref] = w.Offset()
+	for _, s := range ctxt.nonpkgrefs {
+		w.Sym(s)
+	}
+
+	// Referenced package symbol flags
+	h.Offsets[goobj.BlkRefFlags] = w.Offset()
+	w.refFlags()
+
+	// Hashes
+	h.Offsets[goobj.BlkHash64] = w.Offset()
+	for _, s := range ctxt.hashed64defs {
+		w.Hash64(s)
+	}
+	h.Offsets[goobj.BlkHash] = w.Offset()
+	for _, s := range ctxt.hasheddefs {
+		w.Hash(s)
+	}
+	// TODO: hashedrefs unused/unsupported for now
+
+	// Reloc indexes
+	h.Offsets[goobj.BlkRelocIdx] = w.Offset()
+	nreloc := uint32(0)
+	lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
+	for _, list := range lists {
+		for _, s := range list {
+			w.Uint32(nreloc)
+			nreloc += uint32(len(s.R))
+		}
+	}
+	w.Uint32(nreloc)
+
+	// Symbol Info indexes
+	h.Offsets[goobj.BlkAuxIdx] = w.Offset()
+	naux := uint32(0)
+	for _, list := range lists {
+		for _, s := range list {
+			w.Uint32(naux)
+			naux += uint32(nAuxSym(s))
+		}
+	}
+	w.Uint32(naux)
+
+	// Data indexes
+	h.Offsets[goobj.BlkDataIdx] = w.Offset()
+	dataOff := uint32(0)
+	for _, list := range lists {
+		for _, s := range list {
+			w.Uint32(dataOff)
+			dataOff += uint32(len(s.P))
+		}
+	}
+	w.Uint32(dataOff)
+
+	// Relocs
+	h.Offsets[goobj.BlkReloc] = w.Offset()
+	for _, list := range lists {
+		for _, s := range list {
+			for i := range s.R {
+				w.Reloc(&s.R[i])
+			}
+		}
+	}
+
+	// Aux symbol info
+	h.Offsets[goobj.BlkAux] = w.Offset()
+	for _, list := range lists {
+		for _, s := range list {
+			w.Aux(s)
+		}
+	}
+
+	// Data
+	h.Offsets[goobj.BlkData] = w.Offset()
+	for _, list := range lists {
+		for _, s := range list {
+			w.Bytes(s.P)
+		}
+	}
+
+	// Pcdata
+	h.Offsets[goobj.BlkPcdata] = w.Offset()
+	for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
+		if s.Func != nil {
+			pc := &s.Func.Pcln
+			w.Bytes(pc.Pcsp.P)
+			w.Bytes(pc.Pcfile.P)
+			w.Bytes(pc.Pcline.P)
+			w.Bytes(pc.Pcinline.P)
+			for i := range pc.Pcdata {
+				w.Bytes(pc.Pcdata[i].P)
+			}
+		}
+	}
+
+	// Blocks used only by tools (objdump, nm).
+
+	// Referenced symbol names from other packages
+	h.Offsets[goobj.BlkRefName] = w.Offset()
+	w.refNames()
+
+	h.Offsets[goobj.BlkEnd] = w.Offset()
+
+	// Fix up block offsets in the header
+	end := start + int64(w.Offset())
+	b.MustSeek(start, 0)
+	h.Write(w.Writer)
+	b.MustSeek(end, 0)
+}
+
+type writer struct {
+	*goobj.Writer
+	ctxt    *Link
+	pkgpath string   // the package import path (escaped), "" if unknown
+	pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
+}
+
+// prepare package index list
+func (w *writer) init() {
+	w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
+	w.pkglist[0] = "" // dummy invalid package for index 0
+	for pkg, i := range w.ctxt.pkgIdx {
+		w.pkglist[i] = pkg
+	}
+}
+
+func (w *writer) StringTable() {
+	w.AddString("")
+	for _, p := range w.ctxt.Imports {
+		w.AddString(p.Pkg)
+	}
+	for _, pkg := range w.pkglist {
+		w.AddString(pkg)
+	}
+	w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
+		// TODO: this includes references of indexed symbols from other packages,
+		// for which the linker doesn't need the name. Consider moving them to
+		// a separate block (for tools only).
+		if w.pkgpath != "" {
+			s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
+		}
+		// Don't put names of builtins into the string table (to save
+		// space).
+		if s.PkgIdx == goobj.PkgIdxBuiltin {
+			return
+		}
+		w.AddString(s.Name)
+	})
+
+	// All filenames are in the postable.
+	for _, f := range w.ctxt.PosTable.FileTable() {
+		w.AddString(filepath.ToSlash(f))
+	}
+}
+
+func (w *writer) Sym(s *LSym) {
+	abi := uint16(s.ABI())
+	if s.Static() {
+		abi = goobj.SymABIstatic
+	}
+	flag := uint8(0)
+	if s.DuplicateOK() {
+		flag |= goobj.SymFlagDupok
+	}
+	if s.Local() {
+		flag |= goobj.SymFlagLocal
+	}
+	if s.MakeTypelink() {
+		flag |= goobj.SymFlagTypelink
+	}
+	if s.Leaf() {
+		flag |= goobj.SymFlagLeaf
+	}
+	if s.NoSplit() {
+		flag |= goobj.SymFlagNoSplit
+	}
+	if s.ReflectMethod() {
+		flag |= goobj.SymFlagReflectMethod
+	}
+	if s.TopFrame() {
+		flag |= goobj.SymFlagTopFrame
+	}
+	if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
+		flag |= goobj.SymFlagGoType
+	}
+	flag2 := uint8(0)
+	if s.UsedInIface() {
+		flag2 |= goobj.SymFlagUsedInIface
+	}
+	if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
+		flag2 |= goobj.SymFlagItab
+	}
+	name := s.Name
+	if strings.HasPrefix(name, "gofile..") {
+		name = filepath.ToSlash(name)
+	}
+	var align uint32
+	if s.Func != nil {
+		align = uint32(s.Func.Align)
+	}
+	if s.ContentAddressable() {
+		// We generally assume data symbols are natually aligned,
+		// except for strings. If we dedup a string symbol and a
+		// non-string symbol with the same content, we should keep
+		// the largest alignment.
+		// TODO: maybe the compiler could set the alignment for all
+		// data symbols more carefully.
+		if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
+			switch {
+			case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
+				align = 8
+			case s.Size%4 == 0:
+				align = 4
+			case s.Size%2 == 0:
+				align = 2
+			}
+			// don't bother setting align to 1.
+		}
+	}
+	var o goobj.Sym
+	o.SetName(name, w.Writer)
+	o.SetABI(abi)
+	o.SetType(uint8(s.Type))
+	o.SetFlag(flag)
+	o.SetFlag2(flag2)
+	o.SetSiz(uint32(s.Size))
+	o.SetAlign(align)
+	o.Write(w.Writer)
+}
+
+func (w *writer) Hash64(s *LSym) {
+	if !s.ContentAddressable() || len(s.R) != 0 {
+		panic("Hash of non-content-addresable symbol")
+	}
+	b := contentHash64(s)
+	w.Bytes(b[:])
+}
+
+func (w *writer) Hash(s *LSym) {
+	if !s.ContentAddressable() {
+		panic("Hash of non-content-addresable symbol")
+	}
+	b := w.contentHash(s)
+	w.Bytes(b[:])
+}
+
+func contentHash64(s *LSym) goobj.Hash64Type {
+	var b goobj.Hash64Type
+	copy(b[:], s.P)
+	return b
+}
+
+// Compute the content hash for a content-addressable symbol.
+// We build a content hash based on its content and relocations.
+// Depending on the category of the referenced symbol, we choose
+// different hash algorithms such that the hash is globally
+// consistent.
+// - For referenced content-addressable symbol, its content hash
+//   is globally consistent.
+// - For package symbol and builtin symbol, its local index is
+//   globally consistent.
+// - For non-package symbol, its fully-expanded name is globally
+//   consistent. For now, we require we know the current package
+//   path so we can always expand symbol names. (Otherwise,
+//   symbols with relocations are not considered hashable.)
+//
+// For now, we assume there is no circular dependencies among
+// hashed symbols.
+func (w *writer) contentHash(s *LSym) goobj.HashType {
+	h := sha1.New()
+	// The compiler trims trailing zeros _sometimes_. We just do
+	// it always.
+	h.Write(bytes.TrimRight(s.P, "\x00"))
+	var tmp [14]byte
+	for i := range s.R {
+		r := &s.R[i]
+		binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
+		tmp[4] = r.Siz
+		tmp[5] = uint8(r.Type)
+		binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
+		h.Write(tmp[:])
+		rs := r.Sym
+		switch rs.PkgIdx {
+		case goobj.PkgIdxHashed64:
+			h.Write([]byte{0})
+			t := contentHash64(rs)
+			h.Write(t[:])
+		case goobj.PkgIdxHashed:
+			h.Write([]byte{1})
+			t := w.contentHash(rs)
+			h.Write(t[:])
+		case goobj.PkgIdxNone:
+			h.Write([]byte{2})
+			io.WriteString(h, rs.Name) // name is already expanded at this point
+		case goobj.PkgIdxBuiltin:
+			h.Write([]byte{3})
+			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
+			h.Write(tmp[:4])
+		case goobj.PkgIdxSelf:
+			io.WriteString(h, w.pkgpath)
+			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
+			h.Write(tmp[:4])
+		default:
+			io.WriteString(h, rs.Pkg)
+			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
+			h.Write(tmp[:4])
+		}
+	}
+	var b goobj.HashType
+	copy(b[:], h.Sum(nil))
+	return b
+}
+
+func makeSymRef(s *LSym) goobj.SymRef {
+	if s == nil {
+		return goobj.SymRef{}
+	}
+	if s.PkgIdx == 0 || !s.Indexed() {
+		fmt.Printf("unindexed symbol reference: %v\n", s)
+		panic("unindexed symbol reference")
+	}
+	return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
+}
+
+func (w *writer) Reloc(r *Reloc) {
+	var o goobj.Reloc
+	o.SetOff(r.Off)
+	o.SetSiz(r.Siz)
+	o.SetType(uint8(r.Type))
+	o.SetAdd(r.Add)
+	o.SetSym(makeSymRef(r.Sym))
+	o.Write(w.Writer)
+}
+
+func (w *writer) aux1(typ uint8, rs *LSym) {
+	var o goobj.Aux
+	o.SetType(typ)
+	o.SetSym(makeSymRef(rs))
+	o.Write(w.Writer)
+}
+
+func (w *writer) Aux(s *LSym) {
+	if s.Gotype != nil {
+		w.aux1(goobj.AuxGotype, s.Gotype)
+	}
+	if s.Func != nil {
+		w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
+
+		for _, d := range s.Func.Pcln.Funcdata {
+			w.aux1(goobj.AuxFuncdata, d)
+		}
+
+		if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
+			w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
+		}
+		if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
+			w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
+		}
+		if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
+			w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
+		}
+		if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
+			w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
+		}
+	}
+}
+
+// Emits flags of referenced indexed symbols.
+func (w *writer) refFlags() {
+	seen := make(map[*LSym]bool)
+	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
+		switch rs.PkgIdx {
+		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
+			return
+		case goobj.PkgIdxInvalid:
+			panic("unindexed symbol reference")
+		}
+		if seen[rs] {
+			return
+		}
+		seen[rs] = true
+		symref := makeSymRef(rs)
+		flag2 := uint8(0)
+		if rs.UsedInIface() {
+			flag2 |= goobj.SymFlagUsedInIface
+		}
+		if flag2 == 0 {
+			return // no need to write zero flags
+		}
+		var o goobj.RefFlags
+		o.SetSym(symref)
+		o.SetFlag2(flag2)
+		o.Write(w.Writer)
+	})
+}
+
+// Emits names of referenced indexed symbols, used by tools (objdump, nm)
+// only.
+func (w *writer) refNames() {
+	seen := make(map[*LSym]bool)
+	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
+		switch rs.PkgIdx {
+		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
+			return
+		case goobj.PkgIdxInvalid:
+			panic("unindexed symbol reference")
+		}
+		if seen[rs] {
+			return
+		}
+		seen[rs] = true
+		symref := makeSymRef(rs)
+		var o goobj.RefName
+		o.SetSym(symref)
+		o.SetName(rs.Name, w.Writer)
+		o.Write(w.Writer)
+	})
+	// TODO: output in sorted order?
+	// Currently tools (cmd/internal/goobj package) doesn't use mmap,
+	// and it just read it into a map in memory upfront. If it uses
+	// mmap, if the output is sorted, it probably could avoid reading
+	// into memory and just do lookups in the mmap'd object file.
+}
+
+// return the number of aux symbols s have.
+func nAuxSym(s *LSym) int {
+	n := 0
+	if s.Gotype != nil {
+		n++
+	}
+	if s.Func != nil {
+		// FuncInfo is an aux symbol, each Funcdata is an aux symbol
+		n += 1 + len(s.Func.Pcln.Funcdata)
+		if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
+			n++
+		}
+		if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
+			n++
+		}
+		if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
+			n++
+		}
+		if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
+			n++
+		}
+	}
+	return n
+}
+
+// generate symbols for FuncInfo.
+func genFuncInfoSyms(ctxt *Link) {
+	infosyms := make([]*LSym, 0, len(ctxt.Text))
+	var pcdataoff uint32
+	var b bytes.Buffer
+	symidx := int32(len(ctxt.defs))
+	for _, s := range ctxt.Text {
+		if s.Func == nil {
+			continue
+		}
+		o := goobj.FuncInfo{
+			Args:   uint32(s.Func.Args),
+			Locals: uint32(s.Func.Locals),
+			FuncID: objabi.FuncID(s.Func.FuncID),
+		}
+		pc := &s.Func.Pcln
+		o.Pcsp = pcdataoff
+		pcdataoff += uint32(len(pc.Pcsp.P))
+		o.Pcfile = pcdataoff
+		pcdataoff += uint32(len(pc.Pcfile.P))
+		o.Pcline = pcdataoff
+		pcdataoff += uint32(len(pc.Pcline.P))
+		o.Pcinline = pcdataoff
+		pcdataoff += uint32(len(pc.Pcinline.P))
+		o.Pcdata = make([]uint32, len(pc.Pcdata))
+		for i, pcd := range pc.Pcdata {
+			o.Pcdata[i] = pcdataoff
+			pcdataoff += uint32(len(pcd.P))
+		}
+		o.PcdataEnd = pcdataoff
+		o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
+		for i, x := range pc.Funcdataoff {
+			o.Funcdataoff[i] = uint32(x)
+		}
+		i := 0
+		o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
+		for f := range pc.UsedFiles {
+			o.File[i] = f
+			i++
+		}
+		sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
+		o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
+		for i, inl := range pc.InlTree.nodes {
+			f, l := getFileIndexAndLine(ctxt, inl.Pos)
+			o.InlTree[i] = goobj.InlTreeNode{
+				Parent:   int32(inl.Parent),
+				File:     goobj.CUFileIndex(f),
+				Line:     l,
+				Func:     makeSymRef(inl.Func),
+				ParentPC: inl.ParentPC,
+			}
+		}
+
+		o.Write(&b)
+		isym := &LSym{
+			Type:   objabi.SDATA, // for now, I don't think it matters
+			PkgIdx: goobj.PkgIdxSelf,
+			SymIdx: symidx,
+			P:      append([]byte(nil), b.Bytes()...),
+		}
+		isym.Set(AttrIndexed, true)
+		symidx++
+		infosyms = append(infosyms, isym)
+		s.Func.FuncInfoSym = isym
+		b.Reset()
+
+		dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
+		for _, s := range dwsyms {
+			if s == nil || s.Size == 0 {
+				continue
+			}
+			s.PkgIdx = goobj.PkgIdxSelf
+			s.SymIdx = symidx
+			s.Set(AttrIndexed, true)
+			symidx++
+			infosyms = append(infosyms, s)
+		}
+	}
+	ctxt.defs = append(ctxt.defs, infosyms...)
+}
+
+// debugDumpAux is a dumper for selected aux symbols.
+func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
+	// Most aux symbols (ex: funcdata) are not interesting--
+	// pick out just the DWARF ones for now.
+	if aux.Type != objabi.SDWARFLOC &&
+		aux.Type != objabi.SDWARFFCN &&
+		aux.Type != objabi.SDWARFABSFCN &&
+		aux.Type != objabi.SDWARFLINES &&
+		aux.Type != objabi.SDWARFRANGE {
+		return
+	}
+	ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
+}
+
+func debugAsmEmit(ctxt *Link) {
+	if ctxt.Debugasm > 0 {
+		ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
+		if ctxt.Debugasm > 1 {
+			fn := func(par *LSym, aux *LSym) {
+				writeAuxSymDebug(ctxt, par, aux)
+			}
+			ctxt.traverseAuxSyms(traverseAux, fn)
+		}
+	}
+}
+
 func (ctxt *Link) writeSymDebug(s *LSym) {
 	ctxt.writeSymDebugNamed(s, s.Name)
 }
@@ -101,492 +745,3 @@
 func (x relocByOff) Len() int           { return len(x) }
 func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
 func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
-
-// implement dwarf.Context
-type dwCtxt struct{ *Link }
-
-func (c dwCtxt) PtrSize() int {
-	return c.Arch.PtrSize
-}
-func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
-	ls := s.(*LSym)
-	ls.WriteInt(c.Link, ls.Size, size, i)
-}
-func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
-	c.AddInt(s, 2, int64(i))
-}
-func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
-	b := []byte{byte(i)}
-	c.AddBytes(s, b)
-}
-func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
-	ls := s.(*LSym)
-	ls.WriteBytes(c.Link, ls.Size, b)
-}
-func (c dwCtxt) AddString(s dwarf.Sym, v string) {
-	ls := s.(*LSym)
-	ls.WriteString(c.Link, ls.Size, len(v), v)
-	ls.WriteInt(c.Link, ls.Size, 1, 0)
-}
-func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
-	ls := s.(*LSym)
-	size := c.PtrSize()
-	if data != nil {
-		rsym := data.(*LSym)
-		ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
-	} else {
-		ls.WriteInt(c.Link, ls.Size, size, value)
-	}
-}
-func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
-	ls := s.(*LSym)
-	rsym := data.(*LSym)
-	ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
-}
-func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
-	panic("should be used only in the linker")
-}
-func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
-	size := 4
-	if isDwarf64(c.Link) {
-		size = 8
-	}
-
-	ls := s.(*LSym)
-	rsym := t.(*LSym)
-	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
-	r := &ls.R[len(ls.R)-1]
-	r.Type = objabi.R_DWARFSECREF
-}
-
-func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
-	ls := s.(*LSym)
-	rsym := f.(*LSym)
-	fidx := c.Link.PosTable.FileIndex(rsym.Name)
-	// Note the +1 here -- the value we're writing is going to be an
-	// index into the DWARF line table file section, whose entries
-	// are numbered starting at 1, not 0.
-	ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
-}
-
-func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
-	ls := s.(*LSym)
-	return ls.Size
-}
-
-// Here "from" is a symbol corresponding to an inlined or concrete
-// function, "to" is the symbol for the corresponding abstract
-// function, and "dclIdx" is the index of the symbol of interest with
-// respect to the Dcl slice of the original pre-optimization version
-// of the inlined function.
-func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
-	ls := from.(*LSym)
-	tls := to.(*LSym)
-	ridx := len(ls.R) - 1
-	c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
-}
-
-func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
-	ls := s.(*LSym)
-	c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
-}
-
-func (c dwCtxt) Logf(format string, args ...interface{}) {
-	c.Link.Logf(format, args...)
-}
-
-func isDwarf64(ctxt *Link) bool {
-	return ctxt.Headtype == objabi.Haix
-}
-
-func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
-	if s.Type != objabi.STEXT {
-		ctxt.Diag("dwarfSym of non-TEXT %v", s)
-	}
-	if s.Func.dwarfInfoSym == nil {
-		s.Func.dwarfInfoSym = &LSym{
-			Type: objabi.SDWARFFCN,
-		}
-		if ctxt.Flag_locationlists {
-			s.Func.dwarfLocSym = &LSym{
-				Type: objabi.SDWARFLOC,
-			}
-		}
-		s.Func.dwarfRangesSym = &LSym{
-			Type: objabi.SDWARFRANGE,
-		}
-		s.Func.dwarfDebugLinesSym = &LSym{
-			Type: objabi.SDWARFLINES,
-		}
-		if s.WasInlined() {
-			s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
-		}
-	}
-	return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
-}
-
-func (s *LSym) Length(dwarfContext interface{}) int64 {
-	return s.Size
-}
-
-// fileSymbol returns a symbol corresponding to the source file of the
-// first instruction (prog) of the specified function. This will
-// presumably be the file in which the function is defined.
-func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
-	p := fn.Func.Text
-	if p != nil {
-		f, _ := linkgetlineFromPos(ctxt, p.Pos)
-		fsym := ctxt.Lookup(f)
-		return fsym
-	}
-	return nil
-}
-
-// populateDWARF fills in the DWARF Debugging Information Entries for
-// TEXT symbol 's'. The various DWARF symbols must already have been
-// initialized in InitTextSym.
-func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
-	info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
-	if info.Size != 0 {
-		ctxt.Diag("makeFuncDebugEntry double process %v", s)
-	}
-	var scopes []dwarf.Scope
-	var inlcalls dwarf.InlCalls
-	if ctxt.DebugInfo != nil {
-		scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
-	}
-	var err error
-	dwctxt := dwCtxt{ctxt}
-	filesym := ctxt.fileSymbol(s)
-	fnstate := &dwarf.FnState{
-		Name:          s.Name,
-		Importpath:    myimportpath,
-		Info:          info,
-		Filesym:       filesym,
-		Loc:           loc,
-		Ranges:        ranges,
-		Absfn:         absfunc,
-		StartPC:       s,
-		Size:          s.Size,
-		External:      !s.Static(),
-		Scopes:        scopes,
-		InlCalls:      inlcalls,
-		UseBASEntries: ctxt.UseBASEntries,
-	}
-	if absfunc != nil {
-		err = dwarf.PutAbstractFunc(dwctxt, fnstate)
-		if err != nil {
-			ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
-		}
-		err = dwarf.PutConcreteFunc(dwctxt, fnstate)
-	} else {
-		err = dwarf.PutDefaultFunc(dwctxt, fnstate)
-	}
-	if err != nil {
-		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
-	}
-	// Fill in the debug lines symbol.
-	ctxt.generateDebugLinesSymbol(s, lines)
-}
-
-// DwarfIntConst creates a link symbol for an integer constant with the
-// given name, type and value.
-func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
-	if myimportpath == "" {
-		return
-	}
-	s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
-		s.Type = objabi.SDWARFCONST
-		ctxt.Data = append(ctxt.Data, s)
-	})
-	dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
-}
-
-func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
-	absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
-	if absfn.Size != 0 {
-		ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
-	}
-	if s.Func == nil {
-		s.Func = new(FuncInfo)
-	}
-	scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
-	dwctxt := dwCtxt{ctxt}
-	filesym := ctxt.fileSymbol(s)
-	fnstate := dwarf.FnState{
-		Name:          s.Name,
-		Importpath:    myimportpath,
-		Info:          absfn,
-		Filesym:       filesym,
-		Absfn:         absfn,
-		External:      !s.Static(),
-		Scopes:        scopes,
-		UseBASEntries: ctxt.UseBASEntries,
-	}
-	if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
-		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
-	}
-}
-
-// This table is designed to aid in the creation of references between
-// DWARF subprogram DIEs.
-//
-// In most cases when one DWARF DIE has to refer to another DWARF DIE,
-// the target of the reference has an LSym, which makes it easy to use
-// the existing relocation mechanism. For DWARF inlined routine DIEs,
-// however, the subprogram DIE has to refer to a child
-// parameter/variable DIE of the abstract subprogram. This child DIE
-// doesn't have an LSym, and also of interest is the fact that when
-// DWARF generation is happening for inlined function F within caller
-// G, it's possible that DWARF generation hasn't happened yet for F,
-// so there is no way to know the offset of a child DIE within F's
-// abstract function. Making matters more complex, each inlined
-// instance of F may refer to a subset of the original F's variables
-// (depending on what happens with optimization, some vars may be
-// eliminated).
-//
-// The fixup table below helps overcome this hurdle. At the point
-// where a parameter/variable reference is made (via a call to
-// "ReferenceChildDIE"), a fixup record is generate that records
-// the relocation that is targeting that child variable. At a later
-// point when the abstract function DIE is emitted, there will be
-// a call to "RegisterChildDIEOffsets", at which point the offsets
-// needed to apply fixups are captured. Finally, once the parallel
-// portion of the compilation is done, fixups can actually be applied
-// during the "Finalize" method (this can't be done during the
-// parallel portion of the compile due to the possibility of data
-// races).
-//
-// This table is also used to record the "precursor" function node for
-// each function that is the target of an inline -- child DIE references
-// have to be made with respect to the original pre-optimization
-// version of the function (to allow for the fact that each inlined
-// body may be optimized differently).
-type DwarfFixupTable struct {
-	ctxt      *Link
-	mu        sync.Mutex
-	symtab    map[*LSym]int // maps abstract fn LSYM to index in svec
-	svec      []symFixups
-	precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
-}
-
-type symFixups struct {
-	fixups   []relFixup
-	doffsets []declOffset
-	inlIndex int32
-	defseen  bool
-}
-
-type declOffset struct {
-	// Index of variable within DCL list of pre-optimization function
-	dclIdx int32
-	// Offset of var's child DIE with respect to containing subprogram DIE
-	offset int32
-}
-
-type relFixup struct {
-	refsym *LSym
-	relidx int32
-	dclidx int32
-}
-
-type fnState struct {
-	// precursor function (really *gc.Node)
-	precursor interface{}
-	// abstract function symbol
-	absfn *LSym
-}
-
-func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
-	return &DwarfFixupTable{
-		ctxt:      ctxt,
-		symtab:    make(map[*LSym]int),
-		precursor: make(map[*LSym]fnState),
-	}
-}
-
-func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
-	if fnstate, found := ft.precursor[s]; found {
-		return fnstate.precursor
-	}
-	return nil
-}
-
-func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
-	if _, found := ft.precursor[s]; found {
-		ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
-	}
-
-	// initialize abstract function symbol now. This is done here so
-	// as to avoid data races later on during the parallel portion of
-	// the back end.
-	absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
-	absfn.Set(AttrDuplicateOK, true)
-	absfn.Type = objabi.SDWARFABSFCN
-	ft.ctxt.Data = append(ft.ctxt.Data, absfn)
-
-	// In the case of "late" inlining (inlines that happen during
-	// wrapper generation as opposed to the main inlining phase) it's
-	// possible that we didn't cache the abstract function sym for the
-	// text symbol -- do so now if needed. See issue 38068.
-	if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
-		s.Func.dwarfAbsFnSym = absfn
-	}
-
-	ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
-}
-
-// Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
-// is targeting child 'c' of DIE with symbol 'tgt'.
-func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
-	// Protect against concurrent access if multiple backend workers
-	ft.mu.Lock()
-	defer ft.mu.Unlock()
-
-	// Create entry for symbol if not already present.
-	idx, found := ft.symtab[tgt]
-	if !found {
-		ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
-		idx = len(ft.svec) - 1
-		ft.symtab[tgt] = idx
-	}
-
-	// Do we have child DIE offsets available? If so, then apply them,
-	// otherwise create a fixup record.
-	sf := &ft.svec[idx]
-	if len(sf.doffsets) > 0 {
-		found := false
-		for _, do := range sf.doffsets {
-			if do.dclIdx == int32(dclidx) {
-				off := do.offset
-				s.R[ridx].Add += int64(off)
-				found = true
-				break
-			}
-		}
-		if !found {
-			ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
-		}
-	} else {
-		sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
-	}
-}
-
-// Called once DWARF generation is complete for a given abstract function,
-// whose children might have been referenced via a call above. Stores
-// the offsets for any child DIEs (vars, params) so that they can be
-// consumed later in on DwarfFixupTable.Finalize, which applies any
-// outstanding fixups.
-func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
-	// Length of these two slices should agree
-	if len(vars) != len(coffsets) {
-		ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
-		return
-	}
-
-	// Generate the slice of declOffset's based in vars/coffsets
-	doffsets := make([]declOffset, len(coffsets))
-	for i := range coffsets {
-		doffsets[i].dclIdx = vars[i].ChildIndex
-		doffsets[i].offset = coffsets[i]
-	}
-
-	ft.mu.Lock()
-	defer ft.mu.Unlock()
-
-	// Store offsets for this symbol.
-	idx, found := ft.symtab[s]
-	if !found {
-		sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
-		ft.svec = append(ft.svec, sf)
-		ft.symtab[s] = len(ft.svec) - 1
-	} else {
-		sf := &ft.svec[idx]
-		sf.doffsets = doffsets
-		sf.defseen = true
-	}
-}
-
-func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
-	sf := &ft.svec[slot]
-	for _, f := range sf.fixups {
-		dfound := false
-		for _, doffset := range sf.doffsets {
-			if doffset.dclIdx == f.dclidx {
-				f.refsym.R[f.relidx].Add += int64(doffset.offset)
-				dfound = true
-				break
-			}
-		}
-		if !dfound {
-			ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
-		}
-	}
-}
-
-// return the LSym corresponding to the 'abstract subprogram' DWARF
-// info entry for a function.
-func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
-	// Protect against concurrent access if multiple backend workers
-	ft.mu.Lock()
-	defer ft.mu.Unlock()
-
-	if fnstate, found := ft.precursor[fnsym]; found {
-		return fnstate.absfn
-	}
-	ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
-	return nil
-}
-
-// Called after all functions have been compiled; the main job of this
-// function is to identify cases where there are outstanding fixups.
-// This scenario crops up when we have references to variables of an
-// inlined routine, but that routine is defined in some other package.
-// This helper walks through and locate these fixups, then invokes a
-// helper to create an abstract subprogram DIE for each one.
-func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
-	if trace {
-		ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
-	}
-
-	// Collect up the keys from the precursor map, then sort the
-	// resulting list (don't want to rely on map ordering here).
-	fns := make([]*LSym, len(ft.precursor))
-	idx := 0
-	for fn := range ft.precursor {
-		fns[idx] = fn
-		idx++
-	}
-	sort.Sort(BySymName(fns))
-
-	// Should not be called during parallel portion of compilation.
-	if ft.ctxt.InParallel {
-		ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
-	}
-
-	// Generate any missing abstract functions.
-	for _, s := range fns {
-		absfn := ft.AbsFuncDwarfSym(s)
-		slot, found := ft.symtab[absfn]
-		if !found || !ft.svec[slot].defseen {
-			ft.ctxt.GenAbstractFunc(s)
-		}
-	}
-
-	// Apply fixups.
-	for _, s := range fns {
-		absfn := ft.AbsFuncDwarfSym(s)
-		slot, found := ft.symtab[absfn]
-		if !found {
-			ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
-		} else {
-			ft.processFixups(slot, s)
-		}
-	}
-}
-
-type BySymName []*LSym
-
-func (s BySymName) Len() int           { return len(s) }
-func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
-func (s BySymName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
diff --git a/src/cmd/internal/obj/objfile2.go b/src/cmd/internal/obj/objfile2.go
deleted file mode 100644
index f9720f0..0000000
--- a/src/cmd/internal/obj/objfile2.go
+++ /dev/null
@@ -1,658 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Writing Go object files.
-
-package obj
-
-import (
-	"bytes"
-	"cmd/internal/bio"
-	"cmd/internal/goobj"
-	"cmd/internal/objabi"
-	"crypto/sha1"
-	"encoding/binary"
-	"fmt"
-	"io"
-	"path/filepath"
-	"sort"
-	"strings"
-)
-
-// Entry point of writing new object file.
-func WriteObjFile(ctxt *Link, b *bio.Writer) {
-
-	debugAsmEmit(ctxt)
-
-	genFuncInfoSyms(ctxt)
-
-	w := writer{
-		Writer:  goobj.NewWriter(b),
-		ctxt:    ctxt,
-		pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
-	}
-
-	start := b.Offset()
-	w.init()
-
-	// Header
-	// We just reserve the space. We'll fill in the offsets later.
-	flags := uint32(0)
-	if ctxt.Flag_shared {
-		flags |= goobj.ObjFlagShared
-	}
-	if w.pkgpath == "" {
-		flags |= goobj.ObjFlagNeedNameExpansion
-	}
-	if ctxt.IsAsm {
-		flags |= goobj.ObjFlagFromAssembly
-	}
-	h := goobj.Header{
-		Magic:       goobj.Magic,
-		Fingerprint: ctxt.Fingerprint,
-		Flags:       flags,
-	}
-	h.Write(w.Writer)
-
-	// String table
-	w.StringTable()
-
-	// Autolib
-	h.Offsets[goobj.BlkAutolib] = w.Offset()
-	for i := range ctxt.Imports {
-		ctxt.Imports[i].Write(w.Writer)
-	}
-
-	// Package references
-	h.Offsets[goobj.BlkPkgIdx] = w.Offset()
-	for _, pkg := range w.pkglist {
-		w.StringRef(pkg)
-	}
-
-	// File table (for DWARF and pcln generation).
-	h.Offsets[goobj.BlkFile] = w.Offset()
-	for _, f := range ctxt.PosTable.FileTable() {
-		w.StringRef(filepath.ToSlash(f))
-	}
-
-	// Symbol definitions
-	h.Offsets[goobj.BlkSymdef] = w.Offset()
-	for _, s := range ctxt.defs {
-		w.Sym(s)
-	}
-
-	// Short hashed symbol definitions
-	h.Offsets[goobj.BlkHashed64def] = w.Offset()
-	for _, s := range ctxt.hashed64defs {
-		w.Sym(s)
-	}
-
-	// Hashed symbol definitions
-	h.Offsets[goobj.BlkHasheddef] = w.Offset()
-	for _, s := range ctxt.hasheddefs {
-		w.Sym(s)
-	}
-
-	// Non-pkg symbol definitions
-	h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
-	for _, s := range ctxt.nonpkgdefs {
-		w.Sym(s)
-	}
-
-	// Non-pkg symbol references
-	h.Offsets[goobj.BlkNonpkgref] = w.Offset()
-	for _, s := range ctxt.nonpkgrefs {
-		w.Sym(s)
-	}
-
-	// Referenced package symbol flags
-	h.Offsets[goobj.BlkRefFlags] = w.Offset()
-	w.refFlags()
-
-	// Hashes
-	h.Offsets[goobj.BlkHash64] = w.Offset()
-	for _, s := range ctxt.hashed64defs {
-		w.Hash64(s)
-	}
-	h.Offsets[goobj.BlkHash] = w.Offset()
-	for _, s := range ctxt.hasheddefs {
-		w.Hash(s)
-	}
-	// TODO: hashedrefs unused/unsupported for now
-
-	// Reloc indexes
-	h.Offsets[goobj.BlkRelocIdx] = w.Offset()
-	nreloc := uint32(0)
-	lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
-	for _, list := range lists {
-		for _, s := range list {
-			w.Uint32(nreloc)
-			nreloc += uint32(len(s.R))
-		}
-	}
-	w.Uint32(nreloc)
-
-	// Symbol Info indexes
-	h.Offsets[goobj.BlkAuxIdx] = w.Offset()
-	naux := uint32(0)
-	for _, list := range lists {
-		for _, s := range list {
-			w.Uint32(naux)
-			naux += uint32(nAuxSym(s))
-		}
-	}
-	w.Uint32(naux)
-
-	// Data indexes
-	h.Offsets[goobj.BlkDataIdx] = w.Offset()
-	dataOff := uint32(0)
-	for _, list := range lists {
-		for _, s := range list {
-			w.Uint32(dataOff)
-			dataOff += uint32(len(s.P))
-		}
-	}
-	w.Uint32(dataOff)
-
-	// Relocs
-	h.Offsets[goobj.BlkReloc] = w.Offset()
-	for _, list := range lists {
-		for _, s := range list {
-			for i := range s.R {
-				w.Reloc(&s.R[i])
-			}
-		}
-	}
-
-	// Aux symbol info
-	h.Offsets[goobj.BlkAux] = w.Offset()
-	for _, list := range lists {
-		for _, s := range list {
-			w.Aux(s)
-		}
-	}
-
-	// Data
-	h.Offsets[goobj.BlkData] = w.Offset()
-	for _, list := range lists {
-		for _, s := range list {
-			w.Bytes(s.P)
-		}
-	}
-
-	// Pcdata
-	h.Offsets[goobj.BlkPcdata] = w.Offset()
-	for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
-		if s.Func != nil {
-			pc := &s.Func.Pcln
-			w.Bytes(pc.Pcsp.P)
-			w.Bytes(pc.Pcfile.P)
-			w.Bytes(pc.Pcline.P)
-			w.Bytes(pc.Pcinline.P)
-			for i := range pc.Pcdata {
-				w.Bytes(pc.Pcdata[i].P)
-			}
-		}
-	}
-
-	// Blocks used only by tools (objdump, nm).
-
-	// Referenced symbol names from other packages
-	h.Offsets[goobj.BlkRefName] = w.Offset()
-	w.refNames()
-
-	h.Offsets[goobj.BlkEnd] = w.Offset()
-
-	// Fix up block offsets in the header
-	end := start + int64(w.Offset())
-	b.MustSeek(start, 0)
-	h.Write(w.Writer)
-	b.MustSeek(end, 0)
-}
-
-type writer struct {
-	*goobj.Writer
-	ctxt    *Link
-	pkgpath string   // the package import path (escaped), "" if unknown
-	pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
-}
-
-// prepare package index list
-func (w *writer) init() {
-	w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
-	w.pkglist[0] = "" // dummy invalid package for index 0
-	for pkg, i := range w.ctxt.pkgIdx {
-		w.pkglist[i] = pkg
-	}
-}
-
-func (w *writer) StringTable() {
-	w.AddString("")
-	for _, p := range w.ctxt.Imports {
-		w.AddString(p.Pkg)
-	}
-	for _, pkg := range w.pkglist {
-		w.AddString(pkg)
-	}
-	w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
-		// TODO: this includes references of indexed symbols from other packages,
-		// for which the linker doesn't need the name. Consider moving them to
-		// a separate block (for tools only).
-		if w.pkgpath != "" {
-			s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
-		}
-		// Don't put names of builtins into the string table (to save
-		// space).
-		if s.PkgIdx == goobj.PkgIdxBuiltin {
-			return
-		}
-		w.AddString(s.Name)
-	})
-
-	// All filenames are in the postable.
-	for _, f := range w.ctxt.PosTable.FileTable() {
-		w.AddString(filepath.ToSlash(f))
-	}
-}
-
-func (w *writer) Sym(s *LSym) {
-	abi := uint16(s.ABI())
-	if s.Static() {
-		abi = goobj.SymABIstatic
-	}
-	flag := uint8(0)
-	if s.DuplicateOK() {
-		flag |= goobj.SymFlagDupok
-	}
-	if s.Local() {
-		flag |= goobj.SymFlagLocal
-	}
-	if s.MakeTypelink() {
-		flag |= goobj.SymFlagTypelink
-	}
-	if s.Leaf() {
-		flag |= goobj.SymFlagLeaf
-	}
-	if s.NoSplit() {
-		flag |= goobj.SymFlagNoSplit
-	}
-	if s.ReflectMethod() {
-		flag |= goobj.SymFlagReflectMethod
-	}
-	if s.TopFrame() {
-		flag |= goobj.SymFlagTopFrame
-	}
-	if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
-		flag |= goobj.SymFlagGoType
-	}
-	flag2 := uint8(0)
-	if s.UsedInIface() {
-		flag2 |= goobj.SymFlagUsedInIface
-	}
-	if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
-		flag2 |= goobj.SymFlagItab
-	}
-	name := s.Name
-	if strings.HasPrefix(name, "gofile..") {
-		name = filepath.ToSlash(name)
-	}
-	var align uint32
-	if s.Func != nil {
-		align = uint32(s.Func.Align)
-	}
-	if s.ContentAddressable() {
-		// We generally assume data symbols are natually aligned,
-		// except for strings. If we dedup a string symbol and a
-		// non-string symbol with the same content, we should keep
-		// the largest alignment.
-		// TODO: maybe the compiler could set the alignment for all
-		// data symbols more carefully.
-		if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
-			switch {
-			case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
-				align = 8
-			case s.Size%4 == 0:
-				align = 4
-			case s.Size%2 == 0:
-				align = 2
-			}
-			// don't bother setting align to 1.
-		}
-	}
-	var o goobj.Sym
-	o.SetName(name, w.Writer)
-	o.SetABI(abi)
-	o.SetType(uint8(s.Type))
-	o.SetFlag(flag)
-	o.SetFlag2(flag2)
-	o.SetSiz(uint32(s.Size))
-	o.SetAlign(align)
-	o.Write(w.Writer)
-}
-
-func (w *writer) Hash64(s *LSym) {
-	if !s.ContentAddressable() || len(s.R) != 0 {
-		panic("Hash of non-content-addresable symbol")
-	}
-	b := contentHash64(s)
-	w.Bytes(b[:])
-}
-
-func (w *writer) Hash(s *LSym) {
-	if !s.ContentAddressable() {
-		panic("Hash of non-content-addresable symbol")
-	}
-	b := w.contentHash(s)
-	w.Bytes(b[:])
-}
-
-func contentHash64(s *LSym) goobj.Hash64Type {
-	var b goobj.Hash64Type
-	copy(b[:], s.P)
-	return b
-}
-
-// Compute the content hash for a content-addressable symbol.
-// We build a content hash based on its content and relocations.
-// Depending on the category of the referenced symbol, we choose
-// different hash algorithms such that the hash is globally
-// consistent.
-// - For referenced content-addressable symbol, its content hash
-//   is globally consistent.
-// - For package symbol and builtin symbol, its local index is
-//   globally consistent.
-// - For non-package symbol, its fully-expanded name is globally
-//   consistent. For now, we require we know the current package
-//   path so we can always expand symbol names. (Otherwise,
-//   symbols with relocations are not considered hashable.)
-//
-// For now, we assume there is no circular dependencies among
-// hashed symbols.
-func (w *writer) contentHash(s *LSym) goobj.HashType {
-	h := sha1.New()
-	// The compiler trims trailing zeros _sometimes_. We just do
-	// it always.
-	h.Write(bytes.TrimRight(s.P, "\x00"))
-	var tmp [14]byte
-	for i := range s.R {
-		r := &s.R[i]
-		binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
-		tmp[4] = r.Siz
-		tmp[5] = uint8(r.Type)
-		binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
-		h.Write(tmp[:])
-		rs := r.Sym
-		switch rs.PkgIdx {
-		case goobj.PkgIdxHashed64:
-			h.Write([]byte{0})
-			t := contentHash64(rs)
-			h.Write(t[:])
-		case goobj.PkgIdxHashed:
-			h.Write([]byte{1})
-			t := w.contentHash(rs)
-			h.Write(t[:])
-		case goobj.PkgIdxNone:
-			h.Write([]byte{2})
-			io.WriteString(h, rs.Name) // name is already expanded at this point
-		case goobj.PkgIdxBuiltin:
-			h.Write([]byte{3})
-			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
-			h.Write(tmp[:4])
-		case goobj.PkgIdxSelf:
-			io.WriteString(h, w.pkgpath)
-			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
-			h.Write(tmp[:4])
-		default:
-			io.WriteString(h, rs.Pkg)
-			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
-			h.Write(tmp[:4])
-		}
-	}
-	var b goobj.HashType
-	copy(b[:], h.Sum(nil))
-	return b
-}
-
-func makeSymRef(s *LSym) goobj.SymRef {
-	if s == nil {
-		return goobj.SymRef{}
-	}
-	if s.PkgIdx == 0 || !s.Indexed() {
-		fmt.Printf("unindexed symbol reference: %v\n", s)
-		panic("unindexed symbol reference")
-	}
-	return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
-}
-
-func (w *writer) Reloc(r *Reloc) {
-	var o goobj.Reloc
-	o.SetOff(r.Off)
-	o.SetSiz(r.Siz)
-	o.SetType(uint8(r.Type))
-	o.SetAdd(r.Add)
-	o.SetSym(makeSymRef(r.Sym))
-	o.Write(w.Writer)
-}
-
-func (w *writer) aux1(typ uint8, rs *LSym) {
-	var o goobj.Aux
-	o.SetType(typ)
-	o.SetSym(makeSymRef(rs))
-	o.Write(w.Writer)
-}
-
-func (w *writer) Aux(s *LSym) {
-	if s.Gotype != nil {
-		w.aux1(goobj.AuxGotype, s.Gotype)
-	}
-	if s.Func != nil {
-		w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
-
-		for _, d := range s.Func.Pcln.Funcdata {
-			w.aux1(goobj.AuxFuncdata, d)
-		}
-
-		if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
-			w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
-		}
-		if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
-			w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
-		}
-		if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
-			w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
-		}
-		if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
-			w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
-		}
-	}
-}
-
-// Emits flags of referenced indexed symbols.
-func (w *writer) refFlags() {
-	seen := make(map[*LSym]bool)
-	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
-		switch rs.PkgIdx {
-		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
-			return
-		case goobj.PkgIdxInvalid:
-			panic("unindexed symbol reference")
-		}
-		if seen[rs] {
-			return
-		}
-		seen[rs] = true
-		symref := makeSymRef(rs)
-		flag2 := uint8(0)
-		if rs.UsedInIface() {
-			flag2 |= goobj.SymFlagUsedInIface
-		}
-		if flag2 == 0 {
-			return // no need to write zero flags
-		}
-		var o goobj.RefFlags
-		o.SetSym(symref)
-		o.SetFlag2(flag2)
-		o.Write(w.Writer)
-	})
-}
-
-// Emits names of referenced indexed symbols, used by tools (objdump, nm)
-// only.
-func (w *writer) refNames() {
-	seen := make(map[*LSym]bool)
-	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
-		switch rs.PkgIdx {
-		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
-			return
-		case goobj.PkgIdxInvalid:
-			panic("unindexed symbol reference")
-		}
-		if seen[rs] {
-			return
-		}
-		seen[rs] = true
-		symref := makeSymRef(rs)
-		var o goobj.RefName
-		o.SetSym(symref)
-		o.SetName(rs.Name, w.Writer)
-		o.Write(w.Writer)
-	})
-	// TODO: output in sorted order?
-	// Currently tools (cmd/internal/goobj package) doesn't use mmap,
-	// and it just read it into a map in memory upfront. If it uses
-	// mmap, if the output is sorted, it probably could avoid reading
-	// into memory and just do lookups in the mmap'd object file.
-}
-
-// return the number of aux symbols s have.
-func nAuxSym(s *LSym) int {
-	n := 0
-	if s.Gotype != nil {
-		n++
-	}
-	if s.Func != nil {
-		// FuncInfo is an aux symbol, each Funcdata is an aux symbol
-		n += 1 + len(s.Func.Pcln.Funcdata)
-		if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
-			n++
-		}
-		if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
-			n++
-		}
-		if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
-			n++
-		}
-		if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
-			n++
-		}
-	}
-	return n
-}
-
-// generate symbols for FuncInfo.
-func genFuncInfoSyms(ctxt *Link) {
-	infosyms := make([]*LSym, 0, len(ctxt.Text))
-	var pcdataoff uint32
-	var b bytes.Buffer
-	symidx := int32(len(ctxt.defs))
-	for _, s := range ctxt.Text {
-		if s.Func == nil {
-			continue
-		}
-		o := goobj.FuncInfo{
-			Args:   uint32(s.Func.Args),
-			Locals: uint32(s.Func.Locals),
-			FuncID: objabi.FuncID(s.Func.FuncID),
-		}
-		pc := &s.Func.Pcln
-		o.Pcsp = pcdataoff
-		pcdataoff += uint32(len(pc.Pcsp.P))
-		o.Pcfile = pcdataoff
-		pcdataoff += uint32(len(pc.Pcfile.P))
-		o.Pcline = pcdataoff
-		pcdataoff += uint32(len(pc.Pcline.P))
-		o.Pcinline = pcdataoff
-		pcdataoff += uint32(len(pc.Pcinline.P))
-		o.Pcdata = make([]uint32, len(pc.Pcdata))
-		for i, pcd := range pc.Pcdata {
-			o.Pcdata[i] = pcdataoff
-			pcdataoff += uint32(len(pcd.P))
-		}
-		o.PcdataEnd = pcdataoff
-		o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
-		for i, x := range pc.Funcdataoff {
-			o.Funcdataoff[i] = uint32(x)
-		}
-		i := 0
-		o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
-		for f := range pc.UsedFiles {
-			o.File[i] = f
-			i++
-		}
-		sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
-		o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
-		for i, inl := range pc.InlTree.nodes {
-			f, l := getFileIndexAndLine(ctxt, inl.Pos)
-			o.InlTree[i] = goobj.InlTreeNode{
-				Parent:   int32(inl.Parent),
-				File:     goobj.CUFileIndex(f),
-				Line:     l,
-				Func:     makeSymRef(inl.Func),
-				ParentPC: inl.ParentPC,
-			}
-		}
-
-		o.Write(&b)
-		isym := &LSym{
-			Type:   objabi.SDATA, // for now, I don't think it matters
-			PkgIdx: goobj.PkgIdxSelf,
-			SymIdx: symidx,
-			P:      append([]byte(nil), b.Bytes()...),
-		}
-		isym.Set(AttrIndexed, true)
-		symidx++
-		infosyms = append(infosyms, isym)
-		s.Func.FuncInfoSym = isym
-		b.Reset()
-
-		dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
-		for _, s := range dwsyms {
-			if s == nil || s.Size == 0 {
-				continue
-			}
-			s.PkgIdx = goobj.PkgIdxSelf
-			s.SymIdx = symidx
-			s.Set(AttrIndexed, true)
-			symidx++
-			infosyms = append(infosyms, s)
-		}
-	}
-	ctxt.defs = append(ctxt.defs, infosyms...)
-}
-
-// debugDumpAux is a dumper for selected aux symbols.
-func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
-	// Most aux symbols (ex: funcdata) are not interesting--
-	// pick out just the DWARF ones for now.
-	if aux.Type != objabi.SDWARFLOC &&
-		aux.Type != objabi.SDWARFFCN &&
-		aux.Type != objabi.SDWARFABSFCN &&
-		aux.Type != objabi.SDWARFLINES &&
-		aux.Type != objabi.SDWARFRANGE {
-		return
-	}
-	ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
-}
-
-func debugAsmEmit(ctxt *Link) {
-	if ctxt.Debugasm > 0 {
-		ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
-		if ctxt.Debugasm > 1 {
-			fn := func(par *LSym, aux *LSym) {
-				writeAuxSymDebug(ctxt, par, aux)
-			}
-			ctxt.traverseAuxSyms(traverseAux, fn)
-		}
-	}
-}