github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/obj.go (about)

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