github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 "crypto/sha256" 10 "fmt" 11 "io" 12 "strconv" 13 ) 14 15 // architecture-independent object file output 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 // add globals 108 for _, n := range externdcl { 109 if n.Op != ONAME { 110 continue 111 } 112 113 if n.Type == nil { 114 Fatalf("external %v nil type\n", n) 115 } 116 if n.Class == PFUNC { 117 continue 118 } 119 if n.Sym.Pkg != localpkg { 120 continue 121 } 122 dowidth(n.Type) 123 ggloblnod(n) 124 } 125 126 for _, n := range funcsyms { 127 dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0) 128 ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA) 129 } 130 131 // Do not reprocess funcsyms on next dumpglobls call. 132 funcsyms = nil 133 } 134 135 func Bputname(b *obj.Biobuf, s *obj.LSym) { 136 obj.Bwritestring(b, s.Name) 137 obj.Bputc(b, 0) 138 } 139 140 func Linksym(s *Sym) *obj.LSym { 141 if s == nil { 142 return nil 143 } 144 if s.Lsym != nil { 145 return s.Lsym 146 } 147 var name string 148 if isblanksym(s) { 149 name = "_" 150 } else if s.Linkname != "" { 151 name = s.Linkname 152 } else { 153 name = s.Pkg.Prefix + "." + s.Name 154 } 155 156 ls := obj.Linklookup(Ctxt, name, 0) 157 s.Lsym = ls 158 return ls 159 } 160 161 func duintxx(s *Sym, off int, v uint64, wid int) int { 162 return duintxxLSym(Linksym(s), off, v, wid) 163 } 164 165 func duintxxLSym(s *obj.LSym, off int, v uint64, wid int) int { 166 // Update symbol data directly instead of generating a 167 // DATA instruction that liblink will have to interpret later. 168 // This reduces compilation time and memory usage. 169 off = int(Rnd(int64(off), int64(wid))) 170 171 return int(obj.Setuintxx(Ctxt, s, int64(off), v, int64(wid))) 172 } 173 174 func duint8(s *Sym, off int, v uint8) int { 175 return duintxx(s, off, uint64(v), 1) 176 } 177 178 func duint16(s *Sym, off int, v uint16) int { 179 return duintxx(s, off, uint64(v), 2) 180 } 181 182 func duint32(s *Sym, off int, v uint32) int { 183 return duintxx(s, off, uint64(v), 4) 184 } 185 186 func duintptr(s *Sym, off int, v uint64) int { 187 return duintxx(s, off, v, Widthptr) 188 } 189 190 // stringConstantSyms holds the pair of symbols we create for a 191 // constant string. 192 type stringConstantSyms struct { 193 hdr *obj.LSym // string header 194 data *obj.LSym // actual string data 195 } 196 197 // stringConstants maps from the symbol name we use for the string 198 // contents to the pair of linker symbols for that string. 199 var stringConstants = make(map[string]stringConstantSyms, 100) 200 201 func stringsym(s string) (hdr, data *obj.LSym) { 202 var symname string 203 if len(s) > 100 { 204 // Huge strings are hashed to avoid long names in object files. 205 // Indulge in some paranoia by writing the length of s, too, 206 // as protection against length extension attacks. 207 h := sha256.New() 208 io.WriteString(h, s) 209 symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil)) 210 } else { 211 // Small strings get named directly by their contents. 212 symname = strconv.Quote(s) 213 } 214 215 const prefix = "go.string." 216 symdataname := prefix + symname 217 218 // All the strings have the same prefix, so ignore it for map 219 // purposes, but use a slice of the symbol name string to 220 // reduce long-term memory overhead. 221 key := symdataname[len(prefix):] 222 223 if syms, ok := stringConstants[key]; ok { 224 return syms.hdr, syms.data 225 } 226 227 symhdrname := "go.string.hdr." + symname 228 229 symhdr := obj.Linklookup(Ctxt, symhdrname, 0) 230 symdata := obj.Linklookup(Ctxt, symdataname, 0) 231 232 stringConstants[key] = stringConstantSyms{symhdr, symdata} 233 234 // string header 235 off := 0 236 off = dsymptrLSym(symhdr, off, symdata, 0) 237 off = duintxxLSym(symhdr, off, uint64(len(s)), Widthint) 238 ggloblLSym(symhdr, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL) 239 240 // string data 241 off = dsnameLSym(symdata, 0, s) 242 ggloblLSym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL) 243 244 return symhdr, symdata 245 } 246 247 var slicebytes_gen int 248 249 func slicebytes(nam *Node, s string, len int) { 250 slicebytes_gen++ 251 symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen) 252 sym := Pkglookup(symname, localpkg) 253 sym.Def = newname(sym) 254 255 off := dsname(sym, 0, s) 256 ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL) 257 258 if nam.Op != ONAME { 259 Fatalf("slicebytes %v", nam) 260 } 261 off = int(nam.Xoffset) 262 off = dsymptr(nam.Sym, off, sym, 0) 263 off = duintxx(nam.Sym, off, uint64(len), Widthint) 264 duintxx(nam.Sym, off, uint64(len), Widthint) 265 } 266 267 func Datastring(s string, a *obj.Addr) { 268 _, symdata := stringsym(s) 269 a.Type = obj.TYPE_MEM 270 a.Name = obj.NAME_EXTERN 271 a.Sym = symdata 272 a.Offset = 0 273 a.Etype = uint8(Simtype[TINT]) 274 } 275 276 func datagostring(sval string, a *obj.Addr) { 277 symhdr, _ := stringsym(sval) 278 a.Type = obj.TYPE_MEM 279 a.Name = obj.NAME_EXTERN 280 a.Sym = symhdr 281 a.Offset = 0 282 a.Etype = uint8(TSTRING) 283 } 284 285 func dgostringptr(s *Sym, off int, str string) int { 286 if str == "" { 287 return duintptr(s, off, 0) 288 } 289 return dgostrlitptr(s, off, &str) 290 } 291 292 func dgostrlitptr(s *Sym, off int, lit *string) int { 293 if lit == nil { 294 return duintptr(s, off, 0) 295 } 296 off = int(Rnd(int64(off), int64(Widthptr))) 297 symhdr, _ := stringsym(*lit) 298 Linksym(s).WriteAddr(Ctxt, int64(off), Widthptr, symhdr, 0) 299 off += Widthptr 300 return off 301 } 302 303 func dsname(s *Sym, off int, t string) int { 304 return dsnameLSym(Linksym(s), off, t) 305 } 306 307 func dsnameLSym(s *obj.LSym, off int, t string) int { 308 s.WriteString(Ctxt, int64(off), len(t), t) 309 return off + len(t) 310 } 311 312 func dsymptr(s *Sym, off int, x *Sym, xoff int) int { 313 return dsymptrLSym(Linksym(s), off, Linksym(x), xoff) 314 } 315 316 func dsymptrLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int { 317 off = int(Rnd(int64(off), int64(Widthptr))) 318 s.WriteAddr(Ctxt, int64(off), Widthptr, x, int64(xoff)) 319 off += Widthptr 320 return off 321 } 322 323 func gdata(nam *Node, nr *Node, wid int) { 324 if nam.Op != ONAME { 325 Fatalf("gdata nam op %v", opnames[nam.Op]) 326 } 327 if nam.Sym == nil { 328 Fatalf("gdata nil nam sym") 329 } 330 331 switch nr.Op { 332 case OLITERAL: 333 switch nr.Val().Ctype() { 334 case CTCPLX: 335 gdatacomplex(nam, nr.Val().U.(*Mpcplx)) 336 337 case CTSTR: 338 gdatastring(nam, nr.Val().U.(string)) 339 340 case CTINT, CTRUNE, CTBOOL: 341 i, _ := nr.IntLiteral() 342 Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, wid, i) 343 344 case CTFLT: 345 s := Linksym(nam.Sym) 346 f := nr.Val().U.(*Mpflt).Float64() 347 switch nam.Type.Etype { 348 case TFLOAT32: 349 s.WriteFloat32(Ctxt, nam.Xoffset, float32(f)) 350 case TFLOAT64: 351 s.WriteFloat64(Ctxt, nam.Xoffset, f) 352 } 353 354 default: 355 Fatalf("gdata unhandled OLITERAL %v", nr) 356 } 357 358 case OADDR: 359 if nr.Left.Op != ONAME { 360 Fatalf("gdata ADDR left op %s", opnames[nr.Left.Op]) 361 } 362 to := nr.Left 363 Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(to.Sym), to.Xoffset) 364 365 case ONAME: 366 if nr.Class != PFUNC { 367 Fatalf("gdata NAME not PFUNC %d", nr.Class) 368 } 369 Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(funcsym(nr.Sym)), nr.Xoffset) 370 371 default: 372 Fatalf("gdata unhandled op %v %v\n", nr, opnames[nr.Op]) 373 } 374 } 375 376 func gdatacomplex(nam *Node, cval *Mpcplx) { 377 t := Types[cplxsubtype(nam.Type.Etype)] 378 r := cval.Real.Float64() 379 i := cval.Imag.Float64() 380 s := Linksym(nam.Sym) 381 382 switch t.Etype { 383 case TFLOAT32: 384 s.WriteFloat32(Ctxt, nam.Xoffset, float32(r)) 385 s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i)) 386 case TFLOAT64: 387 s.WriteFloat64(Ctxt, nam.Xoffset, r) 388 s.WriteFloat64(Ctxt, nam.Xoffset+8, i) 389 } 390 } 391 392 func gdatastring(nam *Node, sval string) { 393 s := Linksym(nam.Sym) 394 _, symdata := stringsym(sval) 395 s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0) 396 s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthint, int64(len(sval))) 397 }