Home | History | Annotate | Download | only in gc
      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 /*
     14  * architecture-independent object file output
     15  */
     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 	var externs *NodeList
     76 	if externdcl != nil {
     77 		externs = externdcl.End
     78 	}
     79 
     80 	dumpglobls()
     81 	dumptypestructs()
     82 
     83 	// Dump extra globals.
     84 	tmp := externdcl
     85 
     86 	if externs != nil {
     87 		externdcl = externs.Next
     88 	}
     89 	dumpglobls()
     90 	externdcl = tmp
     91 
     92 	zero := Pkglookup("zerovalue", Runtimepkg)
     93 	ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA)
     94 
     95 	dumpdata()
     96 	obj.Writeobjdirect(Ctxt, bout)
     97 
     98 	if writearchive != 0 {
     99 		bout.Flush()
    100 		size := obj.Boffset(bout) - startobj
    101 		if size&1 != 0 {
    102 			obj.Bputc(bout, 0)
    103 		}
    104 		obj.Bseek(bout, startobj-ArhdrSize, 0)
    105 		formathdr(arhdr[:], "_go_.o", size)
    106 		bout.Write(arhdr[:])
    107 	}
    108 
    109 	obj.Bterm(bout)
    110 }
    111 
    112 func dumpglobls() {
    113 	var n *Node
    114 
    115 	// add globals
    116 	for l := externdcl; l != nil; l = l.Next {
    117 		n = l.N
    118 		if n.Op != ONAME {
    119 			continue
    120 		}
    121 
    122 		if n.Type == nil {
    123 			Fatal("external %v nil type\n", n)
    124 		}
    125 		if n.Class == PFUNC {
    126 			continue
    127 		}
    128 		if n.Sym.Pkg != localpkg {
    129 			continue
    130 		}
    131 		dowidth(n.Type)
    132 
    133 		ggloblnod(n)
    134 	}
    135 
    136 	for l := funcsyms; l != nil; l = l.Next {
    137 		n = l.N
    138 		dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
    139 		ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
    140 	}
    141 
    142 	// Do not reprocess funcsyms on next dumpglobls call.
    143 	funcsyms = nil
    144 }
    145 
    146 func Bputname(b *obj.Biobuf, s *obj.LSym) {
    147 	obj.Bwritestring(b, s.Name)
    148 	obj.Bputc(b, 0)
    149 }
    150 
    151 func Linksym(s *Sym) *obj.LSym {
    152 	if s == nil {
    153 		return nil
    154 	}
    155 	if s.Lsym != nil {
    156 		return s.Lsym
    157 	}
    158 	var name string
    159 	if isblanksym(s) {
    160 		name = "_"
    161 	} else if s.Linkname != "" {
    162 		name = s.Linkname
    163 	} else {
    164 		name = s.Pkg.Prefix + "." + s.Name
    165 	}
    166 
    167 	ls := obj.Linklookup(Ctxt, name, 0)
    168 	s.Lsym = ls
    169 	return ls
    170 }
    171 
    172 func duintxx(s *Sym, off int, v uint64, wid int) int {
    173 	// Update symbol data directly instead of generating a
    174 	// DATA instruction that liblink will have to interpret later.
    175 	// This reduces compilation time and memory usage.
    176 	off = int(Rnd(int64(off), int64(wid)))
    177 
    178 	return int(obj.Setuintxx(Ctxt, Linksym(s), int64(off), v, int64(wid)))
    179 }
    180 
    181 func duint8(s *Sym, off int, v uint8) int {
    182 	return duintxx(s, off, uint64(v), 1)
    183 }
    184 
    185 func duint16(s *Sym, off int, v uint16) int {
    186 	return duintxx(s, off, uint64(v), 2)
    187 }
    188 
    189 func duint32(s *Sym, off int, v uint32) int {
    190 	return duintxx(s, off, uint64(v), 4)
    191 }
    192 
    193 func duint64(s *Sym, off int, v uint64) int {
    194 	return duintxx(s, off, v, 8)
    195 }
    196 
    197 func duintptr(s *Sym, off int, v uint64) int {
    198 	return duintxx(s, off, v, Widthptr)
    199 }
    200 
    201 var stringsym_gen int
    202 
    203 func stringsym(s string) (hdr, data *Sym) {
    204 	var symname string
    205 	var pkg *Pkg
    206 	if len(s) > 100 {
    207 		// huge strings are made static to avoid long names
    208 		stringsym_gen++
    209 		symname = fmt.Sprintf(".gostring.%d", stringsym_gen)
    210 
    211 		pkg = localpkg
    212 	} else {
    213 		// small strings get named by their contents,
    214 		// so that multiple modules using the same string
    215 		// can share it.
    216 		symname = strconv.Quote(s)
    217 		pkg = gostringpkg
    218 	}
    219 
    220 	symhdr := Pkglookup("hdr."+symname, pkg)
    221 	symdata := Pkglookup(symname, pkg)
    222 
    223 	// SymUniq flag indicates that data is generated already
    224 	if symhdr.Flags&SymUniq != 0 {
    225 		return symhdr, symdata
    226 	}
    227 	symhdr.Flags |= SymUniq
    228 	symhdr.Def = newname(symhdr)
    229 
    230 	// string header
    231 	off := 0
    232 	off = dsymptr(symhdr, off, symdata, 0)
    233 	off = duintxx(symhdr, off, uint64(len(s)), Widthint)
    234 	ggloblsym(symhdr, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
    235 
    236 	// string data
    237 	if symdata.Flags&SymUniq != 0 {
    238 		return symhdr, symdata
    239 	}
    240 	symdata.Flags |= SymUniq
    241 	symdata.Def = newname(symdata)
    242 
    243 	off = 0
    244 	var m int
    245 	for n := 0; n < len(s); n += m {
    246 		m = 8
    247 		if m > len(s)-n {
    248 			m = len(s) - n
    249 		}
    250 		off = dsname(symdata, off, s[n:n+m])
    251 	}
    252 
    253 	off = duint8(symdata, off, 0)                // terminating NUL for runtime
    254 	off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment
    255 	ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
    256 
    257 	return symhdr, symdata
    258 }
    259 
    260 var slicebytes_gen int
    261 
    262 func slicebytes(nam *Node, s string, len int) {
    263 	var m int
    264 
    265 	slicebytes_gen++
    266 	symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
    267 	sym := Pkglookup(symname, localpkg)
    268 	sym.Def = newname(sym)
    269 
    270 	off := 0
    271 	for n := 0; n < len; n += m {
    272 		m = 8
    273 		if m > len-n {
    274 			m = len - n
    275 		}
    276 		off = dsname(sym, off, s[n:n+m])
    277 	}
    278 
    279 	ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
    280 
    281 	if nam.Op != ONAME {
    282 		Fatal("slicebytes %v", nam)
    283 	}
    284 	off = int(nam.Xoffset)
    285 	off = dsymptr(nam.Sym, off, sym, 0)
    286 	off = duintxx(nam.Sym, off, uint64(len), Widthint)
    287 	duintxx(nam.Sym, off, uint64(len), Widthint)
    288 }
    289 
    290 func dstringptr(s *Sym, off int, str string) int {
    291 	off = int(Rnd(int64(off), int64(Widthptr)))
    292 	p := Thearch.Gins(obj.ADATA, nil, nil)
    293 	p.From.Type = obj.TYPE_MEM
    294 	p.From.Name = obj.NAME_EXTERN
    295 	p.From.Sym = Linksym(s)
    296 	p.From.Offset = int64(off)
    297 	p.From3 = new(obj.Addr)
    298 	p.From3.Type = obj.TYPE_CONST
    299 	p.From3.Offset = int64(Widthptr)
    300 
    301 	Datastring(str+"\x00", &p.To) // TODO(rsc): Remove NUL
    302 	p.To.Type = obj.TYPE_ADDR
    303 	p.To.Etype = Simtype[TINT]
    304 	off += Widthptr
    305 
    306 	return off
    307 }
    308 
    309 func Datastring(s string, a *obj.Addr) {
    310 	_, symdata := stringsym(s)
    311 	a.Type = obj.TYPE_MEM
    312 	a.Name = obj.NAME_EXTERN
    313 	a.Sym = Linksym(symdata)
    314 	a.Node = symdata.Def
    315 	a.Offset = 0
    316 	a.Etype = Simtype[TINT]
    317 }
    318 
    319 func datagostring(sval string, a *obj.Addr) {
    320 	symhdr, _ := stringsym(sval)
    321 	a.Type = obj.TYPE_MEM
    322 	a.Name = obj.NAME_EXTERN
    323 	a.Sym = Linksym(symhdr)
    324 	a.Node = symhdr.Def
    325 	a.Offset = 0
    326 	a.Etype = TSTRING
    327 }
    328 
    329 func dgostringptr(s *Sym, off int, str string) int {
    330 	if str == "" {
    331 		return duintptr(s, off, 0)
    332 	}
    333 	return dgostrlitptr(s, off, &str)
    334 }
    335 
    336 func dgostrlitptr(s *Sym, off int, lit *string) int {
    337 	if lit == nil {
    338 		return duintptr(s, off, 0)
    339 	}
    340 	off = int(Rnd(int64(off), int64(Widthptr)))
    341 	p := Thearch.Gins(obj.ADATA, nil, nil)
    342 	p.From.Type = obj.TYPE_MEM
    343 	p.From.Name = obj.NAME_EXTERN
    344 	p.From.Sym = Linksym(s)
    345 	p.From.Offset = int64(off)
    346 	p.From3 = new(obj.Addr)
    347 	p.From3.Type = obj.TYPE_CONST
    348 	p.From3.Offset = int64(Widthptr)
    349 	datagostring(*lit, &p.To)
    350 	p.To.Type = obj.TYPE_ADDR
    351 	p.To.Etype = Simtype[TINT]
    352 	off += Widthptr
    353 
    354 	return off
    355 }
    356 
    357 func dsname(s *Sym, off int, t string) int {
    358 	p := Thearch.Gins(obj.ADATA, nil, nil)
    359 	p.From.Type = obj.TYPE_MEM
    360 	p.From.Name = obj.NAME_EXTERN
    361 	p.From.Offset = int64(off)
    362 	p.From.Sym = Linksym(s)
    363 	p.From3 = new(obj.Addr)
    364 	p.From3.Type = obj.TYPE_CONST
    365 	p.From3.Offset = int64(len(t))
    366 
    367 	p.To.Type = obj.TYPE_SCONST
    368 	p.To.Val = t
    369 	return off + len(t)
    370 }
    371 
    372 func dsymptr(s *Sym, off int, x *Sym, xoff int) int {
    373 	off = int(Rnd(int64(off), int64(Widthptr)))
    374 
    375 	p := Thearch.Gins(obj.ADATA, nil, nil)
    376 	p.From.Type = obj.TYPE_MEM
    377 	p.From.Name = obj.NAME_EXTERN
    378 	p.From.Sym = Linksym(s)
    379 	p.From.Offset = int64(off)
    380 	p.From3 = new(obj.Addr)
    381 	p.From3.Type = obj.TYPE_CONST
    382 	p.From3.Offset = int64(Widthptr)
    383 	p.To.Type = obj.TYPE_ADDR
    384 	p.To.Name = obj.NAME_EXTERN
    385 	p.To.Sym = Linksym(x)
    386 	p.To.Offset = int64(xoff)
    387 	off += Widthptr
    388 
    389 	return off
    390 }
    391 
    392 func gdata(nam *Node, nr *Node, wid int) {
    393 	if nr.Op == OLITERAL {
    394 		switch nr.Val().Ctype() {
    395 		case CTCPLX:
    396 			gdatacomplex(nam, nr.Val().U.(*Mpcplx))
    397 			return
    398 
    399 		case CTSTR:
    400 			gdatastring(nam, nr.Val().U.(string))
    401 			return
    402 		}
    403 	}
    404 
    405 	p := Thearch.Gins(obj.ADATA, nam, nr)
    406 	p.From3 = new(obj.Addr)
    407 	p.From3.Type = obj.TYPE_CONST
    408 	p.From3.Offset = int64(wid)
    409 }
    410 
    411 func gdatacomplex(nam *Node, cval *Mpcplx) {
    412 	w := cplxsubtype(int(nam.Type.Etype))
    413 	w = int(Types[w].Width)
    414 
    415 	p := Thearch.Gins(obj.ADATA, nam, nil)
    416 	p.From3 = new(obj.Addr)
    417 	p.From3.Type = obj.TYPE_CONST
    418 	p.From3.Offset = int64(w)
    419 	p.To.Type = obj.TYPE_FCONST
    420 	p.To.Val = mpgetflt(&cval.Real)
    421 
    422 	p = Thearch.Gins(obj.ADATA, nam, nil)
    423 	p.From3 = new(obj.Addr)
    424 	p.From3.Type = obj.TYPE_CONST
    425 	p.From3.Offset = int64(w)
    426 	p.From.Offset += int64(w)
    427 	p.To.Type = obj.TYPE_FCONST
    428 	p.To.Val = mpgetflt(&cval.Imag)
    429 }
    430 
    431 func gdatastring(nam *Node, sval string) {
    432 	var nod1 Node
    433 
    434 	p := Thearch.Gins(obj.ADATA, nam, nil)
    435 	Datastring(sval, &p.To)
    436 	p.From3 = new(obj.Addr)
    437 	p.From3.Type = obj.TYPE_CONST
    438 	p.From3.Offset = Types[Tptr].Width
    439 	p.To.Type = obj.TYPE_ADDR
    440 
    441 	//print("%v\n", p);
    442 
    443 	Nodconst(&nod1, Types[TINT], int64(len(sval)))
    444 
    445 	p = Thearch.Gins(obj.ADATA, nam, &nod1)
    446 	p.From3 = new(obj.Addr)
    447 	p.From3.Type = obj.TYPE_CONST
    448 	p.From3.Offset = int64(Widthint)
    449 	p.From.Offset += int64(Widthptr)
    450 }
    451