github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/obj/objfile2.go (about)

     1  // Copyright 2019 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 Go object files.
     6  
     7  package obj
     8  
     9  import (
    10  	"bytes"
    11  	"github.com/gagliardetto/golang-go/cmd/internal/bio"
    12  	"github.com/gagliardetto/golang-go/cmd/internal/goobj2"
    13  	"github.com/gagliardetto/golang-go/cmd/internal/objabi"
    14  	"fmt"
    15  	"path/filepath"
    16  	"strings"
    17  )
    18  
    19  // Entry point of writing new object file.
    20  func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
    21  	if ctxt.Debugasm > 0 {
    22  		ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
    23  	}
    24  
    25  	genFuncInfoSyms(ctxt)
    26  
    27  	w := writer{
    28  		Writer:  goobj2.NewWriter(b),
    29  		ctxt:    ctxt,
    30  		pkgpath: objabi.PathToPrefix(pkgpath),
    31  	}
    32  
    33  	start := b.Offset()
    34  	w.init()
    35  
    36  	// Header
    37  	// We just reserve the space. We'll fill in the offsets later.
    38  	flags := uint32(0)
    39  	if ctxt.Flag_shared {
    40  		flags |= goobj2.ObjFlagShared
    41  	}
    42  	h := goobj2.Header{Magic: goobj2.Magic, Flags: flags}
    43  	h.Write(w.Writer)
    44  
    45  	// String table
    46  	w.StringTable()
    47  
    48  	// Autolib
    49  	h.Offsets[goobj2.BlkAutolib] = w.Offset()
    50  	for _, pkg := range ctxt.Imports {
    51  		w.StringRef(pkg)
    52  	}
    53  
    54  	// Package references
    55  	h.Offsets[goobj2.BlkPkgIdx] = w.Offset()
    56  	for _, pkg := range w.pkglist {
    57  		w.StringRef(pkg)
    58  	}
    59  
    60  	// DWARF file table
    61  	h.Offsets[goobj2.BlkDwarfFile] = w.Offset()
    62  	for _, f := range ctxt.PosTable.DebugLinesFileTable() {
    63  		w.StringRef(f)
    64  	}
    65  
    66  	// Symbol definitions
    67  	h.Offsets[goobj2.BlkSymdef] = w.Offset()
    68  	for _, s := range ctxt.defs {
    69  		w.Sym(s)
    70  	}
    71  
    72  	// Non-pkg symbol definitions
    73  	h.Offsets[goobj2.BlkNonpkgdef] = w.Offset()
    74  	for _, s := range ctxt.nonpkgdefs {
    75  		w.Sym(s)
    76  	}
    77  
    78  	// Non-pkg symbol references
    79  	h.Offsets[goobj2.BlkNonpkgref] = w.Offset()
    80  	for _, s := range ctxt.nonpkgrefs {
    81  		w.Sym(s)
    82  	}
    83  
    84  	// Reloc indexes
    85  	h.Offsets[goobj2.BlkRelocIdx] = w.Offset()
    86  	nreloc := uint32(0)
    87  	lists := [][]*LSym{ctxt.defs, ctxt.nonpkgdefs}
    88  	for _, list := range lists {
    89  		for _, s := range list {
    90  			w.Uint32(nreloc)
    91  			nreloc += uint32(len(s.R))
    92  		}
    93  	}
    94  	w.Uint32(nreloc)
    95  
    96  	// Symbol Info indexes
    97  	h.Offsets[goobj2.BlkAuxIdx] = w.Offset()
    98  	naux := uint32(0)
    99  	for _, list := range lists {
   100  		for _, s := range list {
   101  			w.Uint32(naux)
   102  			naux += uint32(nAuxSym(s))
   103  		}
   104  	}
   105  	w.Uint32(naux)
   106  
   107  	// Data indexes
   108  	h.Offsets[goobj2.BlkDataIdx] = w.Offset()
   109  	dataOff := uint32(0)
   110  	for _, list := range lists {
   111  		for _, s := range list {
   112  			w.Uint32(dataOff)
   113  			dataOff += uint32(len(s.P))
   114  		}
   115  	}
   116  	w.Uint32(dataOff)
   117  
   118  	// Relocs
   119  	h.Offsets[goobj2.BlkReloc] = w.Offset()
   120  	for _, list := range lists {
   121  		for _, s := range list {
   122  			for i := range s.R {
   123  				w.Reloc(&s.R[i])
   124  			}
   125  		}
   126  	}
   127  
   128  	// Aux symbol info
   129  	h.Offsets[goobj2.BlkAux] = w.Offset()
   130  	for _, list := range lists {
   131  		for _, s := range list {
   132  			w.Aux(s)
   133  		}
   134  	}
   135  
   136  	// Data
   137  	h.Offsets[goobj2.BlkData] = w.Offset()
   138  	for _, list := range lists {
   139  		for _, s := range list {
   140  			w.Bytes(s.P)
   141  		}
   142  	}
   143  
   144  	// Pcdata
   145  	h.Offsets[goobj2.BlkPcdata] = w.Offset()
   146  	for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
   147  		if s.Func != nil {
   148  			pc := &s.Func.Pcln
   149  			w.Bytes(pc.Pcsp.P)
   150  			w.Bytes(pc.Pcfile.P)
   151  			w.Bytes(pc.Pcline.P)
   152  			w.Bytes(pc.Pcinline.P)
   153  			for i := range pc.Pcdata {
   154  				w.Bytes(pc.Pcdata[i].P)
   155  			}
   156  		}
   157  	}
   158  
   159  	// Fix up block offsets in the header
   160  	end := start + int64(w.Offset())
   161  	b.MustSeek(start, 0)
   162  	h.Write(w.Writer)
   163  	b.MustSeek(end, 0)
   164  }
   165  
   166  type writer struct {
   167  	*goobj2.Writer
   168  	ctxt    *Link
   169  	pkgpath string   // the package import path (escaped), "" if unknown
   170  	pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
   171  }
   172  
   173  // prepare package index list
   174  func (w *writer) init() {
   175  	w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
   176  	w.pkglist[0] = "" // dummy invalid package for index 0
   177  	for pkg, i := range w.ctxt.pkgIdx {
   178  		w.pkglist[i] = pkg
   179  	}
   180  }
   181  
   182  func (w *writer) StringTable() {
   183  	w.AddString("")
   184  	for _, pkg := range w.ctxt.Imports {
   185  		w.AddString(pkg)
   186  	}
   187  	for _, pkg := range w.pkglist {
   188  		w.AddString(pkg)
   189  	}
   190  	w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
   191  		if w.pkgpath != "" {
   192  			s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
   193  		}
   194  		w.AddString(s.Name)
   195  	})
   196  	w.ctxt.traverseSyms(traverseDefs, func(s *LSym) {
   197  		if s.Type != objabi.STEXT {
   198  			return
   199  		}
   200  		pc := &s.Func.Pcln
   201  		for _, f := range pc.File {
   202  			w.AddString(filepath.ToSlash(f))
   203  		}
   204  		for _, call := range pc.InlTree.nodes {
   205  			f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
   206  			w.AddString(filepath.ToSlash(f))
   207  		}
   208  	})
   209  	for _, f := range w.ctxt.PosTable.DebugLinesFileTable() {
   210  		w.AddString(f)
   211  	}
   212  }
   213  
   214  func (w *writer) Sym(s *LSym) {
   215  	abi := uint16(s.ABI())
   216  	if s.Static() {
   217  		abi = goobj2.SymABIstatic
   218  	}
   219  	flag := uint8(0)
   220  	if s.DuplicateOK() {
   221  		flag |= goobj2.SymFlagDupok
   222  	}
   223  	if s.Local() {
   224  		flag |= goobj2.SymFlagLocal
   225  	}
   226  	if s.MakeTypelink() {
   227  		flag |= goobj2.SymFlagTypelink
   228  	}
   229  	if s.Leaf() {
   230  		flag |= goobj2.SymFlagLeaf
   231  	}
   232  	if s.CFunc() {
   233  		flag |= goobj2.SymFlagCFunc
   234  	}
   235  	if s.ReflectMethod() {
   236  		flag |= goobj2.SymFlagReflectMethod
   237  	}
   238  	if s.TopFrame() {
   239  		flag |= goobj2.SymFlagTopFrame
   240  	}
   241  	if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
   242  		flag |= goobj2.SymFlagGoType
   243  	}
   244  	name := s.Name
   245  	if strings.HasPrefix(name, "gofile..") {
   246  		name = filepath.ToSlash(name)
   247  	}
   248  	o := goobj2.Sym{
   249  		Name: name,
   250  		ABI:  abi,
   251  		Type: uint8(s.Type),
   252  		Flag: flag,
   253  		Siz:  uint32(s.Size),
   254  	}
   255  	o.Write(w.Writer)
   256  }
   257  
   258  func makeSymRef(s *LSym) goobj2.SymRef {
   259  	if s == nil {
   260  		return goobj2.SymRef{}
   261  	}
   262  	if s.PkgIdx == 0 || !s.Indexed() {
   263  		fmt.Printf("unindexed symbol reference: %v\n", s)
   264  		panic("unindexed symbol reference")
   265  	}
   266  	return goobj2.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
   267  }
   268  
   269  func (w *writer) Reloc(r *Reloc) {
   270  	o := goobj2.Reloc{
   271  		Off:  r.Off,
   272  		Siz:  r.Siz,
   273  		Type: uint8(r.Type),
   274  		Add:  r.Add,
   275  		Sym:  makeSymRef(r.Sym),
   276  	}
   277  	o.Write(w.Writer)
   278  }
   279  
   280  func (w *writer) Aux(s *LSym) {
   281  	if s.Gotype != nil {
   282  		o := goobj2.Aux{
   283  			Type: goobj2.AuxGotype,
   284  			Sym:  makeSymRef(s.Gotype),
   285  		}
   286  		o.Write(w.Writer)
   287  	}
   288  	if s.Func != nil {
   289  		o := goobj2.Aux{
   290  			Type: goobj2.AuxFuncInfo,
   291  			Sym:  makeSymRef(s.Func.FuncInfoSym),
   292  		}
   293  		o.Write(w.Writer)
   294  
   295  		for _, d := range s.Func.Pcln.Funcdata {
   296  			o := goobj2.Aux{
   297  				Type: goobj2.AuxFuncdata,
   298  				Sym:  makeSymRef(d),
   299  			}
   300  			o.Write(w.Writer)
   301  		}
   302  
   303  		if s.Func.dwarfInfoSym != nil {
   304  			o := goobj2.Aux{
   305  				Type: goobj2.AuxDwarfInfo,
   306  				Sym:  makeSymRef(s.Func.dwarfInfoSym),
   307  			}
   308  			o.Write(w.Writer)
   309  		}
   310  		if s.Func.dwarfLocSym != nil {
   311  			o := goobj2.Aux{
   312  				Type: goobj2.AuxDwarfLoc,
   313  				Sym:  makeSymRef(s.Func.dwarfLocSym),
   314  			}
   315  			o.Write(w.Writer)
   316  		}
   317  		if s.Func.dwarfRangesSym != nil {
   318  			o := goobj2.Aux{
   319  				Type: goobj2.AuxDwarfRanges,
   320  				Sym:  makeSymRef(s.Func.dwarfRangesSym),
   321  			}
   322  			o.Write(w.Writer)
   323  		}
   324  		if s.Func.dwarfDebugLinesSym != nil {
   325  			o := goobj2.Aux{
   326  				Type: goobj2.AuxDwarfLines,
   327  				Sym:  makeSymRef(s.Func.dwarfDebugLinesSym),
   328  			}
   329  			o.Write(w.Writer)
   330  		}
   331  	}
   332  }
   333  
   334  // return the number of aux symbols s have.
   335  func nAuxSym(s *LSym) int {
   336  	n := 0
   337  	if s.Gotype != nil {
   338  		n++
   339  	}
   340  	if s.Func != nil {
   341  		// FuncInfo is an aux symbol, each Funcdata is an aux symbol
   342  		n += 1 + len(s.Func.Pcln.Funcdata)
   343  		if s.Func.dwarfInfoSym != nil {
   344  			n++
   345  		}
   346  		if s.Func.dwarfLocSym != nil {
   347  			n++
   348  		}
   349  		if s.Func.dwarfRangesSym != nil {
   350  			n++
   351  		}
   352  		if s.Func.dwarfDebugLinesSym != nil {
   353  			n++
   354  		}
   355  	}
   356  	return n
   357  }
   358  
   359  // generate symbols for FuncInfo.
   360  func genFuncInfoSyms(ctxt *Link) {
   361  	infosyms := make([]*LSym, 0, len(ctxt.Text))
   362  	var pcdataoff uint32
   363  	var b bytes.Buffer
   364  	symidx := int32(len(ctxt.defs))
   365  	for _, s := range ctxt.Text {
   366  		if s.Func == nil {
   367  			continue
   368  		}
   369  		nosplit := uint8(0)
   370  		if s.NoSplit() {
   371  			nosplit = 1
   372  		}
   373  		o := goobj2.FuncInfo{
   374  			NoSplit: nosplit,
   375  			Args:    uint32(s.Func.Args),
   376  			Locals:  uint32(s.Func.Locals),
   377  		}
   378  		pc := &s.Func.Pcln
   379  		o.Pcsp = pcdataoff
   380  		pcdataoff += uint32(len(pc.Pcsp.P))
   381  		o.Pcfile = pcdataoff
   382  		pcdataoff += uint32(len(pc.Pcfile.P))
   383  		o.Pcline = pcdataoff
   384  		pcdataoff += uint32(len(pc.Pcline.P))
   385  		o.Pcinline = pcdataoff
   386  		pcdataoff += uint32(len(pc.Pcinline.P))
   387  		o.Pcdata = make([]uint32, len(pc.Pcdata))
   388  		for i, pcd := range pc.Pcdata {
   389  			o.Pcdata[i] = pcdataoff
   390  			pcdataoff += uint32(len(pcd.P))
   391  		}
   392  		o.PcdataEnd = pcdataoff
   393  		o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
   394  		for i, x := range pc.Funcdataoff {
   395  			o.Funcdataoff[i] = uint32(x)
   396  		}
   397  		o.File = make([]goobj2.SymRef, len(pc.File))
   398  		for i, f := range pc.File {
   399  			fsym := ctxt.Lookup(f)
   400  			o.File[i] = makeSymRef(fsym)
   401  		}
   402  		o.InlTree = make([]goobj2.InlTreeNode, len(pc.InlTree.nodes))
   403  		for i, inl := range pc.InlTree.nodes {
   404  			f, l := linkgetlineFromPos(ctxt, inl.Pos)
   405  			fsym := ctxt.Lookup(f)
   406  			o.InlTree[i] = goobj2.InlTreeNode{
   407  				Parent:   int32(inl.Parent),
   408  				File:     makeSymRef(fsym),
   409  				Line:     l,
   410  				Func:     makeSymRef(inl.Func),
   411  				ParentPC: inl.ParentPC,
   412  			}
   413  		}
   414  
   415  		o.Write(&b)
   416  		isym := &LSym{
   417  			Type:   objabi.SDATA, // for now, I don't think it matters
   418  			PkgIdx: goobj2.PkgIdxSelf,
   419  			SymIdx: symidx,
   420  			P:      append([]byte(nil), b.Bytes()...),
   421  		}
   422  		isym.Set(AttrIndexed, true)
   423  		symidx++
   424  		infosyms = append(infosyms, isym)
   425  		s.Func.FuncInfoSym = isym
   426  		b.Reset()
   427  	}
   428  	ctxt.defs = append(ctxt.defs, infosyms...)
   429  }