...

Source file src/cmd/compile/internal/gc/obj.go

     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/compile/internal/types"
     9		"cmd/internal/bio"
    10		"cmd/internal/obj"
    11		"cmd/internal/objabi"
    12		"cmd/internal/src"
    13		"crypto/sha256"
    14		"encoding/json"
    15		"fmt"
    16		"io"
    17		"sort"
    18		"strconv"
    19	)
    20	
    21	// architecture-independent object file output
    22	const ArhdrSize = 60
    23	
    24	func formathdr(arhdr []byte, name string, size int64) {
    25		copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size))
    26	}
    27	
    28	// These modes say which kind of object file to generate.
    29	// The default use of the toolchain is to set both bits,
    30	// generating a combined compiler+linker object, one that
    31	// serves to describe the package to both the compiler and the linker.
    32	// In fact the compiler and linker read nearly disjoint sections of
    33	// that file, though, so in a distributed build setting it can be more
    34	// efficient to split the output into two files, supplying the compiler
    35	// object only to future compilations and the linker object only to
    36	// future links.
    37	//
    38	// By default a combined object is written, but if -linkobj is specified
    39	// on the command line then the default -o output is a compiler object
    40	// and the -linkobj output is a linker object.
    41	const (
    42		modeCompilerObj = 1 << iota
    43		modeLinkerObj
    44	)
    45	
    46	func dumpobj() {
    47		if linkobj == "" {
    48			dumpobj1(outfile, modeCompilerObj|modeLinkerObj)
    49			return
    50		}
    51		dumpobj1(outfile, modeCompilerObj)
    52		dumpobj1(linkobj, modeLinkerObj)
    53	}
    54	
    55	func dumpobj1(outfile string, mode int) {
    56		bout, err := bio.Create(outfile)
    57		if err != nil {
    58			flusherrors()
    59			fmt.Printf("can't create %s: %v\n", outfile, err)
    60			errorexit()
    61		}
    62		defer bout.Close()
    63		bout.WriteString("!<arch>\n")
    64	
    65		if mode&modeCompilerObj != 0 {
    66			start := startArchiveEntry(bout)
    67			dumpCompilerObj(bout)
    68			finishArchiveEntry(bout, start, "__.PKGDEF")
    69		}
    70		if mode&modeLinkerObj != 0 {
    71			start := startArchiveEntry(bout)
    72			dumpLinkerObj(bout)
    73			finishArchiveEntry(bout, start, "_go_.o")
    74		}
    75	}
    76	
    77	func printObjHeader(bout *bio.Writer) {
    78		fmt.Fprintf(bout, "go object %s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
    79		if buildid != "" {
    80			fmt.Fprintf(bout, "build id %q\n", buildid)
    81		}
    82		if localpkg.Name == "main" {
    83			fmt.Fprintf(bout, "main\n")
    84		}
    85		fmt.Fprintf(bout, "\n") // header ends with blank line
    86	}
    87	
    88	func startArchiveEntry(bout *bio.Writer) int64 {
    89		var arhdr [ArhdrSize]byte
    90		bout.Write(arhdr[:])
    91		return bout.Offset()
    92	}
    93	
    94	func finishArchiveEntry(bout *bio.Writer, start int64, name string) {
    95		bout.Flush()
    96		size := bout.Offset() - start
    97		if size&1 != 0 {
    98			bout.WriteByte(0)
    99		}
   100		bout.MustSeek(start-ArhdrSize, 0)
   101	
   102		var arhdr [ArhdrSize]byte
   103		formathdr(arhdr[:], name, size)
   104		bout.Write(arhdr[:])
   105		bout.Flush()
   106		bout.MustSeek(start+size+(size&1), 0)
   107	}
   108	
   109	func dumpCompilerObj(bout *bio.Writer) {
   110		printObjHeader(bout)
   111		dumpexport(bout)
   112	}
   113	
   114	func dumpLinkerObj(bout *bio.Writer) {
   115		printObjHeader(bout)
   116	
   117		if len(pragcgobuf) != 0 {
   118			// write empty export section; must be before cgo section
   119			fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
   120			fmt.Fprintf(bout, "\n$$  // cgo\n")
   121			if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
   122				Fatalf("serializing pragcgobuf: %v", err)
   123			}
   124			fmt.Fprintf(bout, "\n$$\n\n")
   125		}
   126	
   127		fmt.Fprintf(bout, "\n!\n")
   128	
   129		externs := len(externdcl)
   130	
   131		dumpglobls()
   132		addptabs()
   133		addsignats(externdcl)
   134		dumpsignats()
   135		dumptabs()
   136		dumpimportstrings()
   137		dumpbasictypes()
   138	
   139		// Calls to dumpsignats can generate functions,
   140		// like method wrappers and hash and equality routines.
   141		// Compile any generated functions, process any new resulting types, repeat.
   142		// This can't loop forever, because there is no way to generate an infinite
   143		// number of types in a finite amount of code.
   144		// In the typical case, we loop 0 or 1 times.
   145		// It was not until issue 24761 that we found any code that required a loop at all.
   146		for len(compilequeue) > 0 {
   147			compileFunctions()
   148			dumpsignats()
   149		}
   150	
   151		// Dump extra globals.
   152		tmp := externdcl
   153	
   154		if externdcl != nil {
   155			externdcl = externdcl[externs:]
   156		}
   157		dumpglobls()
   158		externdcl = tmp
   159	
   160		if zerosize > 0 {
   161			zero := mappkg.Lookup("zero")
   162			ggloblsym(zero.Linksym(), int32(zerosize), obj.DUPOK|obj.RODATA)
   163		}
   164	
   165		addGCLocals()
   166	
   167		obj.WriteObjFile(Ctxt, bout.Writer, myimportpath)
   168	}
   169	
   170	func addptabs() {
   171		if !Ctxt.Flag_dynlink || localpkg.Name != "main" {
   172			return
   173		}
   174		for _, exportn := range exportlist {
   175			s := exportn.Sym
   176			n := asNode(s.Def)
   177			if n == nil {
   178				continue
   179			}
   180			if n.Op != ONAME {
   181				continue
   182			}
   183			if !types.IsExported(s.Name) {
   184				continue
   185			}
   186			if s.Pkg.Name != "main" {
   187				continue
   188			}
   189			if n.Type.Etype == TFUNC && n.Class() == PFUNC {
   190				// function
   191				ptabs = append(ptabs, ptabEntry{s: s, t: asNode(s.Def).Type})
   192			} else {
   193				// variable
   194				ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(asNode(s.Def).Type)})
   195			}
   196		}
   197	}
   198	
   199	func dumpGlobal(n *Node) {
   200		if n.Type == nil {
   201			Fatalf("external %v nil type\n", n)
   202		}
   203		if n.Class() == PFUNC {
   204			return
   205		}
   206		if n.Sym.Pkg != localpkg {
   207			return
   208		}
   209		dowidth(n.Type)
   210		ggloblnod(n)
   211	}
   212	
   213	func dumpGlobalConst(n *Node) {
   214		// only export typed constants
   215		t := n.Type
   216		if t == nil {
   217			return
   218		}
   219		if n.Sym.Pkg != localpkg {
   220			return
   221		}
   222		// only export integer constants for now
   223		switch t.Etype {
   224		case TINT8:
   225		case TINT16:
   226		case TINT32:
   227		case TINT64:
   228		case TINT:
   229		case TUINT8:
   230		case TUINT16:
   231		case TUINT32:
   232		case TUINT64:
   233		case TUINT:
   234		case TUINTPTR:
   235			// ok
   236		case TIDEAL:
   237			if !Isconst(n, CTINT) {
   238				return
   239			}
   240			x := n.Val().U.(*Mpint)
   241			if x.Cmp(minintval[TINT]) < 0 || x.Cmp(maxintval[TINT]) > 0 {
   242				return
   243			}
   244			// Ideal integers we export as int (if they fit).
   245			t = types.Types[TINT]
   246		default:
   247			return
   248		}
   249		Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64())
   250	}
   251	
   252	func dumpglobls() {
   253		// add globals
   254		for _, n := range externdcl {
   255			switch n.Op {
   256			case ONAME:
   257				dumpGlobal(n)
   258			case OLITERAL:
   259				dumpGlobalConst(n)
   260			}
   261		}
   262	
   263		sort.Slice(funcsyms, func(i, j int) bool {
   264			return funcsyms[i].LinksymName() < funcsyms[j].LinksymName()
   265		})
   266		for _, s := range funcsyms {
   267			sf := s.Pkg.Lookup(funcsymname(s)).Linksym()
   268			dsymptr(sf, 0, s.Linksym(), 0)
   269			ggloblsym(sf, int32(Widthptr), obj.DUPOK|obj.RODATA)
   270		}
   271	
   272		// Do not reprocess funcsyms on next dumpglobls call.
   273		funcsyms = nil
   274	}
   275	
   276	// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
   277	//
   278	// This is done during the sequential phase after compilation, since
   279	// global symbols can't be declared during parallel compilation.
   280	func addGCLocals() {
   281		for _, s := range Ctxt.Text {
   282			if s.Func == nil {
   283				continue
   284			}
   285			for _, gcsym := range []*obj.LSym{s.Func.GCArgs, s.Func.GCLocals, s.Func.GCRegs} {
   286				if gcsym != nil && !gcsym.OnList() {
   287					ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
   288				}
   289			}
   290			if x := s.Func.StackObjects; x != nil {
   291				ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
   292			}
   293		}
   294	}
   295	
   296	func duintxx(s *obj.LSym, off int, v uint64, wid int) int {
   297		if off&(wid-1) != 0 {
   298			Fatalf("duintxxLSym: misaligned: v=%d wid=%d off=%d", v, wid, off)
   299		}
   300		s.WriteInt(Ctxt, int64(off), wid, int64(v))
   301		return off + wid
   302	}
   303	
   304	func duint8(s *obj.LSym, off int, v uint8) int {
   305		return duintxx(s, off, uint64(v), 1)
   306	}
   307	
   308	func duint16(s *obj.LSym, off int, v uint16) int {
   309		return duintxx(s, off, uint64(v), 2)
   310	}
   311	
   312	func duint32(s *obj.LSym, off int, v uint32) int {
   313		return duintxx(s, off, uint64(v), 4)
   314	}
   315	
   316	func duintptr(s *obj.LSym, off int, v uint64) int {
   317		return duintxx(s, off, v, Widthptr)
   318	}
   319	
   320	func dbvec(s *obj.LSym, off int, bv bvec) int {
   321		// Runtime reads the bitmaps as byte arrays. Oblige.
   322		for j := 0; int32(j) < bv.n; j += 8 {
   323			word := bv.b[j/32]
   324			off = duint8(s, off, uint8(word>>(uint(j)%32)))
   325		}
   326		return off
   327	}
   328	
   329	func stringsym(pos src.XPos, s string) (data *obj.LSym) {
   330		var symname string
   331		if len(s) > 100 {
   332			// Huge strings are hashed to avoid long names in object files.
   333			// Indulge in some paranoia by writing the length of s, too,
   334			// as protection against length extension attacks.
   335			h := sha256.New()
   336			io.WriteString(h, s)
   337			symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil))
   338		} else {
   339			// Small strings get named directly by their contents.
   340			symname = strconv.Quote(s)
   341		}
   342	
   343		const prefix = "go.string."
   344		symdataname := prefix + symname
   345	
   346		symdata := Ctxt.Lookup(symdataname)
   347	
   348		if !symdata.SeenGlobl() {
   349			// string data
   350			off := dsname(symdata, 0, s, pos, "string")
   351			ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
   352		}
   353	
   354		return symdata
   355	}
   356	
   357	var slicebytes_gen int
   358	
   359	func slicebytes(nam *Node, s string, len int) {
   360		slicebytes_gen++
   361		symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
   362		sym := localpkg.Lookup(symname)
   363		sym.Def = asTypesNode(newname(sym))
   364	
   365		lsym := sym.Linksym()
   366		off := dsname(lsym, 0, s, nam.Pos, "slice")
   367		ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL)
   368	
   369		if nam.Op != ONAME {
   370			Fatalf("slicebytes %v", nam)
   371		}
   372		nsym := nam.Sym.Linksym()
   373		off = int(nam.Xoffset)
   374		off = dsymptr(nsym, off, lsym, 0)
   375		off = duintptr(nsym, off, uint64(len))
   376		duintptr(nsym, off, uint64(len))
   377	}
   378	
   379	func dsname(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
   380		// Objects that are too large will cause the data section to overflow right away,
   381		// causing a cryptic error message by the linker. Check for oversize objects here
   382		// and provide a useful error message instead.
   383		if int64(len(t)) > 2e9 {
   384			yyerrorl(pos, "%v with length %v is too big", what, len(t))
   385			return 0
   386		}
   387	
   388		s.WriteString(Ctxt, int64(off), len(t), t)
   389		return off + len(t)
   390	}
   391	
   392	func dsymptr(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
   393		off = int(Rnd(int64(off), int64(Widthptr)))
   394		s.WriteAddr(Ctxt, int64(off), Widthptr, x, int64(xoff))
   395		off += Widthptr
   396		return off
   397	}
   398	
   399	func dsymptrOff(s *obj.LSym, off int, x *obj.LSym) int {
   400		s.WriteOff(Ctxt, int64(off), x, 0)
   401		off += 4
   402		return off
   403	}
   404	
   405	func dsymptrWeakOff(s *obj.LSym, off int, x *obj.LSym) int {
   406		s.WriteWeakOff(Ctxt, int64(off), x, 0)
   407		off += 4
   408		return off
   409	}
   410	
   411	func gdata(nam *Node, nr *Node, wid int) {
   412		if nam.Op != ONAME {
   413			Fatalf("gdata nam op %v", nam.Op)
   414		}
   415		if nam.Sym == nil {
   416			Fatalf("gdata nil nam sym")
   417		}
   418		s := nam.Sym.Linksym()
   419	
   420		switch nr.Op {
   421		case OLITERAL:
   422			switch u := nr.Val().U.(type) {
   423			case bool:
   424				i := int64(obj.Bool2int(u))
   425				s.WriteInt(Ctxt, nam.Xoffset, wid, i)
   426	
   427			case *Mpint:
   428				s.WriteInt(Ctxt, nam.Xoffset, wid, u.Int64())
   429	
   430			case *Mpflt:
   431				f := u.Float64()
   432				switch nam.Type.Etype {
   433				case TFLOAT32:
   434					s.WriteFloat32(Ctxt, nam.Xoffset, float32(f))
   435				case TFLOAT64:
   436					s.WriteFloat64(Ctxt, nam.Xoffset, f)
   437				}
   438	
   439			case *Mpcplx:
   440				r := u.Real.Float64()
   441				i := u.Imag.Float64()
   442				switch nam.Type.Etype {
   443				case TCOMPLEX64:
   444					s.WriteFloat32(Ctxt, nam.Xoffset, float32(r))
   445					s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i))
   446				case TCOMPLEX128:
   447					s.WriteFloat64(Ctxt, nam.Xoffset, r)
   448					s.WriteFloat64(Ctxt, nam.Xoffset+8, i)
   449				}
   450	
   451			case string:
   452				symdata := stringsym(nam.Pos, u)
   453				s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0)
   454				s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthptr, int64(len(u)))
   455	
   456			default:
   457				Fatalf("gdata unhandled OLITERAL %v", nr)
   458			}
   459	
   460		case OADDR:
   461			if nr.Left.Op != ONAME {
   462				Fatalf("gdata ADDR left op %v", nr.Left.Op)
   463			}
   464			to := nr.Left
   465			s.WriteAddr(Ctxt, nam.Xoffset, wid, to.Sym.Linksym(), to.Xoffset)
   466	
   467		case ONAME:
   468			if nr.Class() != PFUNC {
   469				Fatalf("gdata NAME not PFUNC %d", nr.Class())
   470			}
   471			s.WriteAddr(Ctxt, nam.Xoffset, wid, funcsym(nr.Sym).Linksym(), nr.Xoffset)
   472	
   473		default:
   474			Fatalf("gdata unhandled op %v %v\n", nr, nr.Op)
   475		}
   476	}
   477	

View as plain text