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