mirror of
https://github.com/golang/go.git
synced 2025-05-29 03:11:26 +00:00
$ sizeof -p cmd/compile/internal/gc Node Node 144 $ Change-Id: I688e3790964fe42f48c19f697ec38094a92fe1c1 Reviewed-on: https://go-review.googlesource.com/10531 Reviewed-by: Ian Lance Taylor <iant@golang.org>
443 lines
9.4 KiB
Go
443 lines
9.4 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gc
|
|
|
|
import (
|
|
"cmd/internal/obj"
|
|
"fmt"
|
|
"strconv"
|
|
)
|
|
|
|
/*
|
|
* architecture-independent object file output
|
|
*/
|
|
const (
|
|
ArhdrSize = 60
|
|
)
|
|
|
|
func formathdr(arhdr []byte, name string, size int64) {
|
|
copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size))
|
|
}
|
|
|
|
func dumpobj() {
|
|
var err error
|
|
bout, err = obj.Bopenw(outfile)
|
|
if err != nil {
|
|
Flusherrors()
|
|
fmt.Printf("can't create %s: %v\n", outfile, err)
|
|
errorexit()
|
|
}
|
|
|
|
startobj := int64(0)
|
|
var arhdr [ArhdrSize]byte
|
|
if writearchive != 0 {
|
|
obj.Bwritestring(bout, "!<arch>\n")
|
|
arhdr = [ArhdrSize]byte{}
|
|
bout.Write(arhdr[:])
|
|
startobj = obj.Boffset(bout)
|
|
}
|
|
|
|
fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
|
|
dumpexport()
|
|
|
|
if writearchive != 0 {
|
|
bout.Flush()
|
|
size := obj.Boffset(bout) - startobj
|
|
if size&1 != 0 {
|
|
obj.Bputc(bout, 0)
|
|
}
|
|
obj.Bseek(bout, startobj-ArhdrSize, 0)
|
|
formathdr(arhdr[:], "__.PKGDEF", size)
|
|
bout.Write(arhdr[:])
|
|
bout.Flush()
|
|
|
|
obj.Bseek(bout, startobj+size+(size&1), 0)
|
|
arhdr = [ArhdrSize]byte{}
|
|
bout.Write(arhdr[:])
|
|
startobj = obj.Boffset(bout)
|
|
fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
|
|
}
|
|
|
|
if pragcgobuf != "" {
|
|
if writearchive != 0 {
|
|
// write empty export section; must be before cgo section
|
|
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
|
|
}
|
|
|
|
fmt.Fprintf(bout, "\n$$ // cgo\n")
|
|
fmt.Fprintf(bout, "%s\n$$\n\n", pragcgobuf)
|
|
}
|
|
|
|
fmt.Fprintf(bout, "\n!\n")
|
|
|
|
var externs *NodeList
|
|
if externdcl != nil {
|
|
externs = externdcl.End
|
|
}
|
|
|
|
dumpglobls()
|
|
dumptypestructs()
|
|
|
|
// Dump extra globals.
|
|
tmp := externdcl
|
|
|
|
if externs != nil {
|
|
externdcl = externs.Next
|
|
}
|
|
dumpglobls()
|
|
externdcl = tmp
|
|
|
|
zero := Pkglookup("zerovalue", Runtimepkg)
|
|
ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA)
|
|
|
|
dumpdata()
|
|
obj.Writeobjdirect(Ctxt, bout)
|
|
|
|
if writearchive != 0 {
|
|
bout.Flush()
|
|
size := obj.Boffset(bout) - startobj
|
|
if size&1 != 0 {
|
|
obj.Bputc(bout, 0)
|
|
}
|
|
obj.Bseek(bout, startobj-ArhdrSize, 0)
|
|
formathdr(arhdr[:], "_go_.o", size)
|
|
bout.Write(arhdr[:])
|
|
}
|
|
|
|
obj.Bterm(bout)
|
|
}
|
|
|
|
func dumpglobls() {
|
|
var n *Node
|
|
|
|
// add globals
|
|
for l := externdcl; l != nil; l = l.Next {
|
|
n = l.N
|
|
if n.Op != ONAME {
|
|
continue
|
|
}
|
|
|
|
if n.Type == nil {
|
|
Fatal("external %v nil type\n", n)
|
|
}
|
|
if n.Class == PFUNC {
|
|
continue
|
|
}
|
|
if n.Sym.Pkg != localpkg {
|
|
continue
|
|
}
|
|
dowidth(n.Type)
|
|
|
|
ggloblnod(n)
|
|
}
|
|
|
|
for l := funcsyms; l != nil; l = l.Next {
|
|
n = l.N
|
|
dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
|
|
ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
|
|
}
|
|
|
|
// Do not reprocess funcsyms on next dumpglobls call.
|
|
funcsyms = nil
|
|
}
|
|
|
|
func Bputname(b *obj.Biobuf, s *obj.LSym) {
|
|
obj.Bwritestring(b, s.Name)
|
|
obj.Bputc(b, 0)
|
|
}
|
|
|
|
func Linksym(s *Sym) *obj.LSym {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
if s.Lsym != nil {
|
|
return s.Lsym
|
|
}
|
|
var name string
|
|
if isblanksym(s) {
|
|
name = "_"
|
|
} else if s.Linkname != "" {
|
|
name = s.Linkname
|
|
} else {
|
|
name = s.Pkg.Prefix + "." + s.Name
|
|
}
|
|
|
|
ls := obj.Linklookup(Ctxt, name, 0)
|
|
s.Lsym = ls
|
|
return ls
|
|
}
|
|
|
|
func duintxx(s *Sym, off int, v uint64, wid int) int {
|
|
// Update symbol data directly instead of generating a
|
|
// DATA instruction that liblink will have to interpret later.
|
|
// This reduces compilation time and memory usage.
|
|
off = int(Rnd(int64(off), int64(wid)))
|
|
|
|
return int(obj.Setuintxx(Ctxt, Linksym(s), int64(off), v, int64(wid)))
|
|
}
|
|
|
|
func duint8(s *Sym, off int, v uint8) int {
|
|
return duintxx(s, off, uint64(v), 1)
|
|
}
|
|
|
|
func duint16(s *Sym, off int, v uint16) int {
|
|
return duintxx(s, off, uint64(v), 2)
|
|
}
|
|
|
|
func duint32(s *Sym, off int, v uint32) int {
|
|
return duintxx(s, off, uint64(v), 4)
|
|
}
|
|
|
|
func duint64(s *Sym, off int, v uint64) int {
|
|
return duintxx(s, off, v, 8)
|
|
}
|
|
|
|
func duintptr(s *Sym, off int, v uint64) int {
|
|
return duintxx(s, off, v, Widthptr)
|
|
}
|
|
|
|
var stringsym_gen int
|
|
|
|
func stringsym(s string) *Sym {
|
|
var symname string
|
|
var pkg *Pkg
|
|
if len(s) > 100 {
|
|
// huge strings are made static to avoid long names
|
|
stringsym_gen++
|
|
symname = fmt.Sprintf(".gostring.%d", stringsym_gen)
|
|
|
|
pkg = localpkg
|
|
} else {
|
|
// small strings get named by their contents,
|
|
// so that multiple modules using the same string
|
|
// can share it.
|
|
symname = strconv.Quote(s)
|
|
pkg = gostringpkg
|
|
}
|
|
|
|
sym := Pkglookup(symname, pkg)
|
|
|
|
// SymUniq flag indicates that data is generated already
|
|
if sym.Flags&SymUniq != 0 {
|
|
return sym
|
|
}
|
|
sym.Flags |= SymUniq
|
|
sym.Def = newname(sym)
|
|
|
|
off := 0
|
|
|
|
// string header
|
|
off = dsymptr(sym, off, sym, Widthptr+Widthint)
|
|
off = duintxx(sym, off, uint64(len(s)), Widthint)
|
|
|
|
// string data
|
|
var m int
|
|
for n := 0; n < len(s); n += m {
|
|
m = 8
|
|
if m > len(s)-n {
|
|
m = len(s) - n
|
|
}
|
|
off = dsname(sym, off, s[n:n+m])
|
|
}
|
|
|
|
off = duint8(sym, off, 0) // terminating NUL for runtime
|
|
off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment
|
|
ggloblsym(sym, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
|
|
|
return sym
|
|
}
|
|
|
|
var slicebytes_gen int
|
|
|
|
func slicebytes(nam *Node, s string, len int) {
|
|
var m int
|
|
|
|
slicebytes_gen++
|
|
symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
|
|
sym := Pkglookup(symname, localpkg)
|
|
sym.Def = newname(sym)
|
|
|
|
off := 0
|
|
for n := 0; n < len; n += m {
|
|
m = 8
|
|
if m > len-n {
|
|
m = len - n
|
|
}
|
|
off = dsname(sym, off, s[n:n+m])
|
|
}
|
|
|
|
ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
|
|
|
|
if nam.Op != ONAME {
|
|
Fatal("slicebytes %v", nam)
|
|
}
|
|
off = int(nam.Xoffset)
|
|
off = dsymptr(nam.Sym, off, sym, 0)
|
|
off = duintxx(nam.Sym, off, uint64(len), Widthint)
|
|
duintxx(nam.Sym, off, uint64(len), Widthint)
|
|
}
|
|
|
|
func dstringptr(s *Sym, off int, str string) int {
|
|
off = int(Rnd(int64(off), int64(Widthptr)))
|
|
p := Thearch.Gins(obj.ADATA, nil, nil)
|
|
p.From.Type = obj.TYPE_MEM
|
|
p.From.Name = obj.NAME_EXTERN
|
|
p.From.Sym = Linksym(s)
|
|
p.From.Offset = int64(off)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = int64(Widthptr)
|
|
|
|
Datastring(str+"\x00", &p.To) // TODO(rsc): Remove NUL
|
|
p.To.Type = obj.TYPE_ADDR
|
|
p.To.Etype = Simtype[TINT]
|
|
off += Widthptr
|
|
|
|
return off
|
|
}
|
|
|
|
func Datastring(s string, a *obj.Addr) {
|
|
sym := stringsym(s)
|
|
a.Type = obj.TYPE_MEM
|
|
a.Name = obj.NAME_EXTERN
|
|
a.Sym = Linksym(sym)
|
|
a.Node = sym.Def
|
|
a.Offset = int64(Widthptr) + int64(Widthint) // skip header
|
|
a.Etype = Simtype[TINT]
|
|
}
|
|
|
|
func datagostring(sval string, a *obj.Addr) {
|
|
sym := stringsym(sval)
|
|
a.Type = obj.TYPE_MEM
|
|
a.Name = obj.NAME_EXTERN
|
|
a.Sym = Linksym(sym)
|
|
a.Node = sym.Def
|
|
a.Offset = 0 // header
|
|
a.Etype = TSTRING
|
|
}
|
|
|
|
func dgostringptr(s *Sym, off int, str string) int {
|
|
if str == "" {
|
|
return duintptr(s, off, 0)
|
|
}
|
|
return dgostrlitptr(s, off, &str)
|
|
}
|
|
|
|
func dgostrlitptr(s *Sym, off int, lit *string) int {
|
|
if lit == nil {
|
|
return duintptr(s, off, 0)
|
|
}
|
|
off = int(Rnd(int64(off), int64(Widthptr)))
|
|
p := Thearch.Gins(obj.ADATA, nil, nil)
|
|
p.From.Type = obj.TYPE_MEM
|
|
p.From.Name = obj.NAME_EXTERN
|
|
p.From.Sym = Linksym(s)
|
|
p.From.Offset = int64(off)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = int64(Widthptr)
|
|
datagostring(*lit, &p.To)
|
|
p.To.Type = obj.TYPE_ADDR
|
|
p.To.Etype = Simtype[TINT]
|
|
off += Widthptr
|
|
|
|
return off
|
|
}
|
|
|
|
func dsname(s *Sym, off int, t string) int {
|
|
p := Thearch.Gins(obj.ADATA, nil, nil)
|
|
p.From.Type = obj.TYPE_MEM
|
|
p.From.Name = obj.NAME_EXTERN
|
|
p.From.Offset = int64(off)
|
|
p.From.Sym = Linksym(s)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = int64(len(t))
|
|
|
|
p.To.Type = obj.TYPE_SCONST
|
|
p.To.Val = t
|
|
return off + len(t)
|
|
}
|
|
|
|
func dsymptr(s *Sym, off int, x *Sym, xoff int) int {
|
|
off = int(Rnd(int64(off), int64(Widthptr)))
|
|
|
|
p := Thearch.Gins(obj.ADATA, nil, nil)
|
|
p.From.Type = obj.TYPE_MEM
|
|
p.From.Name = obj.NAME_EXTERN
|
|
p.From.Sym = Linksym(s)
|
|
p.From.Offset = int64(off)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = int64(Widthptr)
|
|
p.To.Type = obj.TYPE_ADDR
|
|
p.To.Name = obj.NAME_EXTERN
|
|
p.To.Sym = Linksym(x)
|
|
p.To.Offset = int64(xoff)
|
|
off += Widthptr
|
|
|
|
return off
|
|
}
|
|
|
|
func gdata(nam *Node, nr *Node, wid int) {
|
|
if nr.Op == OLITERAL {
|
|
switch nr.Val().Ctype() {
|
|
case CTCPLX:
|
|
gdatacomplex(nam, nr.Val().U.(*Mpcplx))
|
|
return
|
|
|
|
case CTSTR:
|
|
gdatastring(nam, nr.Val().U.(string))
|
|
return
|
|
}
|
|
}
|
|
|
|
p := Thearch.Gins(obj.ADATA, nam, nr)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = int64(wid)
|
|
}
|
|
|
|
func gdatacomplex(nam *Node, cval *Mpcplx) {
|
|
w := cplxsubtype(int(nam.Type.Etype))
|
|
w = int(Types[w].Width)
|
|
|
|
p := Thearch.Gins(obj.ADATA, nam, nil)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = int64(w)
|
|
p.To.Type = obj.TYPE_FCONST
|
|
p.To.Val = mpgetflt(&cval.Real)
|
|
|
|
p = Thearch.Gins(obj.ADATA, nam, nil)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = int64(w)
|
|
p.From.Offset += int64(w)
|
|
p.To.Type = obj.TYPE_FCONST
|
|
p.To.Val = mpgetflt(&cval.Imag)
|
|
}
|
|
|
|
func gdatastring(nam *Node, sval string) {
|
|
var nod1 Node
|
|
|
|
p := Thearch.Gins(obj.ADATA, nam, nil)
|
|
Datastring(sval, &p.To)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = Types[Tptr].Width
|
|
p.To.Type = obj.TYPE_ADDR
|
|
|
|
//print("%v\n", p);
|
|
|
|
Nodconst(&nod1, Types[TINT], int64(len(sval)))
|
|
|
|
p = Thearch.Gins(obj.ADATA, nam, &nod1)
|
|
p.From3 = new(obj.Addr)
|
|
p.From3.Type = obj.TYPE_CONST
|
|
p.From3.Offset = int64(Widthint)
|
|
p.From.Offset += int64(Widthptr)
|
|
}
|