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