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