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