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