github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/gc/obj.go (about)

     1  // Copyright 2009 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  package gc
     6  
     7  import (
     8  	"cmd/internal/obj"
     9  	"crypto/sha256"
    10  	"fmt"
    11  	"io"
    12  	"strconv"
    13  )
    14  
    15  // architecture-independent object file output
    16  const (
    17  	ArhdrSize = 60
    18  )
    19  
    20  func formathdr(arhdr []byte, name string, size int64) {
    21  	copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size))
    22  }
    23  
    24  func dumpobj() {
    25  	var err error
    26  	bout, err = obj.Bopenw(outfile)
    27  	if err != nil {
    28  		Flusherrors()
    29  		fmt.Printf("can't create %s: %v\n", outfile, err)
    30  		errorexit()
    31  	}
    32  
    33  	startobj := int64(0)
    34  	var arhdr [ArhdrSize]byte
    35  	if writearchive != 0 {
    36  		obj.Bwritestring(bout, "!<arch>\n")
    37  		arhdr = [ArhdrSize]byte{}
    38  		bout.Write(arhdr[:])
    39  		startobj = obj.Boffset(bout)
    40  	}
    41  
    42  	fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
    43  	dumpexport()
    44  
    45  	if writearchive != 0 {
    46  		bout.Flush()
    47  		size := obj.Boffset(bout) - startobj
    48  		if size&1 != 0 {
    49  			obj.Bputc(bout, 0)
    50  		}
    51  		obj.Bseek(bout, startobj-ArhdrSize, 0)
    52  		formathdr(arhdr[:], "__.PKGDEF", size)
    53  		bout.Write(arhdr[:])
    54  		bout.Flush()
    55  
    56  		obj.Bseek(bout, startobj+size+(size&1), 0)
    57  		arhdr = [ArhdrSize]byte{}
    58  		bout.Write(arhdr[:])
    59  		startobj = obj.Boffset(bout)
    60  		fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
    61  	}
    62  
    63  	if pragcgobuf != "" {
    64  		if writearchive != 0 {
    65  			// write empty export section; must be before cgo section
    66  			fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
    67  		}
    68  
    69  		fmt.Fprintf(bout, "\n$$  // cgo\n")
    70  		fmt.Fprintf(bout, "%s\n$$\n\n", pragcgobuf)
    71  	}
    72  
    73  	fmt.Fprintf(bout, "\n!\n")
    74  
    75  	externs := len(externdcl)
    76  
    77  	dumpglobls()
    78  	dumptypestructs()
    79  
    80  	// Dump extra globals.
    81  	tmp := externdcl
    82  
    83  	if externdcl != nil {
    84  		externdcl = externdcl[externs:]
    85  	}
    86  	dumpglobls()
    87  	externdcl = tmp
    88  
    89  	dumpdata()
    90  	obj.Writeobjdirect(Ctxt, bout)
    91  
    92  	if writearchive != 0 {
    93  		bout.Flush()
    94  		size := obj.Boffset(bout) - startobj
    95  		if size&1 != 0 {
    96  			obj.Bputc(bout, 0)
    97  		}
    98  		obj.Bseek(bout, startobj-ArhdrSize, 0)
    99  		formathdr(arhdr[:], "_go_.o", size)
   100  		bout.Write(arhdr[:])
   101  	}
   102  
   103  	obj.Bterm(bout)
   104  }
   105  
   106  func dumpglobls() {
   107  	// add globals
   108  	for _, n := range externdcl {
   109  		if n.Op != ONAME {
   110  			continue
   111  		}
   112  
   113  		if n.Type == nil {
   114  			Fatalf("external %v nil type\n", n)
   115  		}
   116  		if n.Class == PFUNC {
   117  			continue
   118  		}
   119  		if n.Sym.Pkg != localpkg {
   120  			continue
   121  		}
   122  		dowidth(n.Type)
   123  		ggloblnod(n)
   124  	}
   125  
   126  	for _, n := range funcsyms {
   127  		dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
   128  		ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
   129  	}
   130  
   131  	// Do not reprocess funcsyms on next dumpglobls call.
   132  	funcsyms = nil
   133  }
   134  
   135  func Bputname(b *obj.Biobuf, s *obj.LSym) {
   136  	obj.Bwritestring(b, s.Name)
   137  	obj.Bputc(b, 0)
   138  }
   139  
   140  func Linksym(s *Sym) *obj.LSym {
   141  	if s == nil {
   142  		return nil
   143  	}
   144  	if s.Lsym != nil {
   145  		return s.Lsym
   146  	}
   147  	var name string
   148  	if isblanksym(s) {
   149  		name = "_"
   150  	} else if s.Linkname != "" {
   151  		name = s.Linkname
   152  	} else {
   153  		name = s.Pkg.Prefix + "." + s.Name
   154  	}
   155  
   156  	ls := obj.Linklookup(Ctxt, name, 0)
   157  	s.Lsym = ls
   158  	return ls
   159  }
   160  
   161  func duintxx(s *Sym, off int, v uint64, wid int) int {
   162  	return duintxxLSym(Linksym(s), off, v, wid)
   163  }
   164  
   165  func duintxxLSym(s *obj.LSym, off int, v uint64, wid int) int {
   166  	// Update symbol data directly instead of generating a
   167  	// DATA instruction that liblink will have to interpret later.
   168  	// This reduces compilation time and memory usage.
   169  	off = int(Rnd(int64(off), int64(wid)))
   170  
   171  	return int(obj.Setuintxx(Ctxt, s, int64(off), v, int64(wid)))
   172  }
   173  
   174  func duint8(s *Sym, off int, v uint8) int {
   175  	return duintxx(s, off, uint64(v), 1)
   176  }
   177  
   178  func duint16(s *Sym, off int, v uint16) int {
   179  	return duintxx(s, off, uint64(v), 2)
   180  }
   181  
   182  func duint32(s *Sym, off int, v uint32) int {
   183  	return duintxx(s, off, uint64(v), 4)
   184  }
   185  
   186  func duintptr(s *Sym, off int, v uint64) int {
   187  	return duintxx(s, off, v, Widthptr)
   188  }
   189  
   190  // stringConstantSyms holds the pair of symbols we create for a
   191  // constant string.
   192  type stringConstantSyms struct {
   193  	hdr  *obj.LSym // string header
   194  	data *obj.LSym // actual string data
   195  }
   196  
   197  // stringConstants maps from the symbol name we use for the string
   198  // contents to the pair of linker symbols for that string.
   199  var stringConstants = make(map[string]stringConstantSyms, 100)
   200  
   201  func stringsym(s string) (hdr, data *obj.LSym) {
   202  	var symname string
   203  	if len(s) > 100 {
   204  		// Huge strings are hashed to avoid long names in object files.
   205  		// Indulge in some paranoia by writing the length of s, too,
   206  		// as protection against length extension attacks.
   207  		h := sha256.New()
   208  		io.WriteString(h, s)
   209  		symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil))
   210  	} else {
   211  		// Small strings get named directly by their contents.
   212  		symname = strconv.Quote(s)
   213  	}
   214  
   215  	const prefix = "go.string."
   216  	symdataname := prefix + symname
   217  
   218  	// All the strings have the same prefix, so ignore it for map
   219  	// purposes, but use a slice of the symbol name string to
   220  	// reduce long-term memory overhead.
   221  	key := symdataname[len(prefix):]
   222  
   223  	if syms, ok := stringConstants[key]; ok {
   224  		return syms.hdr, syms.data
   225  	}
   226  
   227  	symhdrname := "go.string.hdr." + symname
   228  
   229  	symhdr := obj.Linklookup(Ctxt, symhdrname, 0)
   230  	symdata := obj.Linklookup(Ctxt, symdataname, 0)
   231  
   232  	stringConstants[key] = stringConstantSyms{symhdr, symdata}
   233  
   234  	// string header
   235  	off := 0
   236  	off = dsymptrLSym(symhdr, off, symdata, 0)
   237  	off = duintxxLSym(symhdr, off, uint64(len(s)), Widthint)
   238  	ggloblLSym(symhdr, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
   239  
   240  	// string data
   241  	off = dsnameLSym(symdata, 0, s)
   242  	ggloblLSym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
   243  
   244  	return symhdr, symdata
   245  }
   246  
   247  var slicebytes_gen int
   248  
   249  func slicebytes(nam *Node, s string, len int) {
   250  	slicebytes_gen++
   251  	symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
   252  	sym := Pkglookup(symname, localpkg)
   253  	sym.Def = newname(sym)
   254  
   255  	off := dsname(sym, 0, s)
   256  	ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
   257  
   258  	if nam.Op != ONAME {
   259  		Fatalf("slicebytes %v", nam)
   260  	}
   261  	off = int(nam.Xoffset)
   262  	off = dsymptr(nam.Sym, off, sym, 0)
   263  	off = duintxx(nam.Sym, off, uint64(len), Widthint)
   264  	duintxx(nam.Sym, off, uint64(len), Widthint)
   265  }
   266  
   267  func Datastring(s string, a *obj.Addr) {
   268  	_, symdata := stringsym(s)
   269  	a.Type = obj.TYPE_MEM
   270  	a.Name = obj.NAME_EXTERN
   271  	a.Sym = symdata
   272  	a.Offset = 0
   273  	a.Etype = uint8(Simtype[TINT])
   274  }
   275  
   276  func datagostring(sval string, a *obj.Addr) {
   277  	symhdr, _ := stringsym(sval)
   278  	a.Type = obj.TYPE_MEM
   279  	a.Name = obj.NAME_EXTERN
   280  	a.Sym = symhdr
   281  	a.Offset = 0
   282  	a.Etype = uint8(TSTRING)
   283  }
   284  
   285  func dgostringptr(s *Sym, off int, str string) int {
   286  	if str == "" {
   287  		return duintptr(s, off, 0)
   288  	}
   289  	return dgostrlitptr(s, off, &str)
   290  }
   291  
   292  func dgostrlitptr(s *Sym, off int, lit *string) int {
   293  	if lit == nil {
   294  		return duintptr(s, off, 0)
   295  	}
   296  	off = int(Rnd(int64(off), int64(Widthptr)))
   297  	symhdr, _ := stringsym(*lit)
   298  	Linksym(s).WriteAddr(Ctxt, int64(off), Widthptr, symhdr, 0)
   299  	off += Widthptr
   300  	return off
   301  }
   302  
   303  func dsname(s *Sym, off int, t string) int {
   304  	return dsnameLSym(Linksym(s), off, t)
   305  }
   306  
   307  func dsnameLSym(s *obj.LSym, off int, t string) int {
   308  	s.WriteString(Ctxt, int64(off), len(t), t)
   309  	return off + len(t)
   310  }
   311  
   312  func dsymptr(s *Sym, off int, x *Sym, xoff int) int {
   313  	return dsymptrLSym(Linksym(s), off, Linksym(x), xoff)
   314  }
   315  
   316  func dsymptrLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
   317  	off = int(Rnd(int64(off), int64(Widthptr)))
   318  	s.WriteAddr(Ctxt, int64(off), Widthptr, x, int64(xoff))
   319  	off += Widthptr
   320  	return off
   321  }
   322  
   323  func gdata(nam *Node, nr *Node, wid int) {
   324  	if nam.Op != ONAME {
   325  		Fatalf("gdata nam op %v", opnames[nam.Op])
   326  	}
   327  	if nam.Sym == nil {
   328  		Fatalf("gdata nil nam sym")
   329  	}
   330  
   331  	switch nr.Op {
   332  	case OLITERAL:
   333  		switch nr.Val().Ctype() {
   334  		case CTCPLX:
   335  			gdatacomplex(nam, nr.Val().U.(*Mpcplx))
   336  
   337  		case CTSTR:
   338  			gdatastring(nam, nr.Val().U.(string))
   339  
   340  		case CTINT, CTRUNE, CTBOOL:
   341  			i, _ := nr.IntLiteral()
   342  			Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, wid, i)
   343  
   344  		case CTFLT:
   345  			s := Linksym(nam.Sym)
   346  			f := nr.Val().U.(*Mpflt).Float64()
   347  			switch nam.Type.Etype {
   348  			case TFLOAT32:
   349  				s.WriteFloat32(Ctxt, nam.Xoffset, float32(f))
   350  			case TFLOAT64:
   351  				s.WriteFloat64(Ctxt, nam.Xoffset, f)
   352  			}
   353  
   354  		default:
   355  			Fatalf("gdata unhandled OLITERAL %v", nr)
   356  		}
   357  
   358  	case OADDR:
   359  		if nr.Left.Op != ONAME {
   360  			Fatalf("gdata ADDR left op %s", opnames[nr.Left.Op])
   361  		}
   362  		to := nr.Left
   363  		Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(to.Sym), to.Xoffset)
   364  
   365  	case ONAME:
   366  		if nr.Class != PFUNC {
   367  			Fatalf("gdata NAME not PFUNC %d", nr.Class)
   368  		}
   369  		Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(funcsym(nr.Sym)), nr.Xoffset)
   370  
   371  	default:
   372  		Fatalf("gdata unhandled op %v %v\n", nr, opnames[nr.Op])
   373  	}
   374  }
   375  
   376  func gdatacomplex(nam *Node, cval *Mpcplx) {
   377  	t := Types[cplxsubtype(nam.Type.Etype)]
   378  	r := cval.Real.Float64()
   379  	i := cval.Imag.Float64()
   380  	s := Linksym(nam.Sym)
   381  
   382  	switch t.Etype {
   383  	case TFLOAT32:
   384  		s.WriteFloat32(Ctxt, nam.Xoffset, float32(r))
   385  		s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i))
   386  	case TFLOAT64:
   387  		s.WriteFloat64(Ctxt, nam.Xoffset, r)
   388  		s.WriteFloat64(Ctxt, nam.Xoffset+8, i)
   389  	}
   390  }
   391  
   392  func gdatastring(nam *Node, sval string) {
   393  	s := Linksym(nam.Sym)
   394  	_, symdata := stringsym(sval)
   395  	s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0)
   396  	s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthint, int64(len(sval)))
   397  }