github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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/compile/internal/types" 9 "cmd/internal/bio" 10 "cmd/internal/obj" 11 "cmd/internal/objabi" 12 "crypto/sha256" 13 "fmt" 14 "io" 15 "strconv" 16 ) 17 18 // architecture-independent object file output 19 const ( 20 ArhdrSize = 60 21 ) 22 23 func formathdr(arhdr []byte, name string, size int64) { 24 copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size)) 25 } 26 27 // These modes say which kind of object file to generate. 28 // The default use of the toolchain is to set both bits, 29 // generating a combined compiler+linker object, one that 30 // serves to describe the package to both the compiler and the linker. 31 // In fact the compiler and linker read nearly disjoint sections of 32 // that file, though, so in a distributed build setting it can be more 33 // efficient to split the output into two files, supplying the compiler 34 // object only to future compilations and the linker object only to 35 // future links. 36 // 37 // By default a combined object is written, but if -linkobj is specified 38 // on the command line then the default -o output is a compiler object 39 // and the -linkobj output is a linker object. 40 const ( 41 modeCompilerObj = 1 << iota 42 modeLinkerObj 43 ) 44 45 func dumpobj() { 46 if !dolinkobj { 47 dumpobj1(outfile, modeCompilerObj) 48 return 49 } 50 if linkobj == "" { 51 dumpobj1(outfile, modeCompilerObj|modeLinkerObj) 52 return 53 } 54 dumpobj1(outfile, modeCompilerObj) 55 dumpobj1(linkobj, modeLinkerObj) 56 } 57 58 func dumpobj1(outfile string, mode int) { 59 var err error 60 bout, err = bio.Create(outfile) 61 if err != nil { 62 flusherrors() 63 fmt.Printf("can't create %s: %v\n", outfile, err) 64 errorexit() 65 } 66 67 startobj := int64(0) 68 var arhdr [ArhdrSize]byte 69 if writearchive { 70 bout.WriteString("!<arch>\n") 71 arhdr = [ArhdrSize]byte{} 72 bout.Write(arhdr[:]) 73 startobj = bout.Offset() 74 } 75 76 printheader := func() { 77 fmt.Fprintf(bout, "go object %s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring()) 78 if buildid != "" { 79 fmt.Fprintf(bout, "build id %q\n", buildid) 80 } 81 if localpkg.Name == "main" { 82 fmt.Fprintf(bout, "main\n") 83 } 84 if safemode { 85 fmt.Fprintf(bout, "safe\n") 86 } else { 87 fmt.Fprintf(bout, "----\n") // room for some other tool to write "safe" 88 } 89 fmt.Fprintf(bout, "\n") // header ends with blank line 90 } 91 92 printheader() 93 94 if mode&modeCompilerObj != 0 { 95 dumpexport() 96 } 97 98 if writearchive { 99 bout.Flush() 100 size := bout.Offset() - startobj 101 if size&1 != 0 { 102 bout.WriteByte(0) 103 } 104 bout.Seek(startobj-ArhdrSize, 0) 105 formathdr(arhdr[:], "__.PKGDEF", size) 106 bout.Write(arhdr[:]) 107 bout.Flush() 108 bout.Seek(startobj+size+(size&1), 0) 109 } 110 111 if mode&modeLinkerObj == 0 { 112 bout.Close() 113 return 114 } 115 116 if writearchive { 117 // start object file 118 arhdr = [ArhdrSize]byte{} 119 bout.Write(arhdr[:]) 120 startobj = bout.Offset() 121 printheader() 122 } 123 124 if pragcgobuf != "" { 125 if writearchive { 126 // write empty export section; must be before cgo section 127 fmt.Fprintf(bout, "\n$$\n\n$$\n\n") 128 } 129 130 fmt.Fprintf(bout, "\n$$ // cgo\n") 131 fmt.Fprintf(bout, "%s\n$$\n\n", pragcgobuf) 132 } 133 134 fmt.Fprintf(bout, "\n!\n") 135 136 externs := len(externdcl) 137 138 dumpglobls() 139 addptabs() 140 addsignats(externdcl) 141 dumpsignats() 142 dumptabs() 143 dumpimportstrings() 144 dumpbasictypes() 145 146 // Dump extra globals. 147 tmp := externdcl 148 149 if externdcl != nil { 150 externdcl = externdcl[externs:] 151 } 152 dumpglobls() 153 externdcl = tmp 154 155 if zerosize > 0 { 156 zero := mappkg.Lookup("zero") 157 ggloblsym(zero.Linksym(), int32(zerosize), obj.DUPOK|obj.RODATA) 158 } 159 160 addGCLocals() 161 162 obj.WriteObjFile(Ctxt, bout.Writer) 163 164 if writearchive { 165 bout.Flush() 166 size := bout.Offset() - startobj 167 if size&1 != 0 { 168 bout.WriteByte(0) 169 } 170 bout.Seek(startobj-ArhdrSize, 0) 171 formathdr(arhdr[:], "_go_.o", size) 172 bout.Write(arhdr[:]) 173 } 174 175 bout.Close() 176 } 177 178 func addptabs() { 179 if !Ctxt.Flag_dynlink || localpkg.Name != "main" { 180 return 181 } 182 for _, exportn := range exportlist { 183 s := exportn.Sym 184 n := asNode(s.Def) 185 if n == nil { 186 continue 187 } 188 if n.Op != ONAME { 189 continue 190 } 191 if !exportname(s.Name) { 192 continue 193 } 194 if s.Pkg.Name != "main" { 195 continue 196 } 197 if n.Type.Etype == TFUNC && n.Class() == PFUNC { 198 // function 199 ptabs = append(ptabs, ptabEntry{s: s, t: asNode(s.Def).Type}) 200 } else { 201 // variable 202 ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(asNode(s.Def).Type)}) 203 } 204 } 205 } 206 207 func dumpglobls() { 208 // add globals 209 for _, n := range externdcl { 210 if n.Op != ONAME { 211 continue 212 } 213 214 if n.Type == nil { 215 Fatalf("external %v nil type\n", n) 216 } 217 if n.Class() == PFUNC { 218 continue 219 } 220 if n.Sym.Pkg != localpkg { 221 continue 222 } 223 dowidth(n.Type) 224 ggloblnod(n) 225 } 226 227 obj.SortSlice(funcsyms, func(i, j int) bool { 228 return funcsyms[i].LinksymName() < funcsyms[j].LinksymName() 229 }) 230 for _, s := range funcsyms { 231 sf := s.Pkg.Lookup(funcsymname(s)).Linksym() 232 dsymptr(sf, 0, s.Linksym(), 0) 233 ggloblsym(sf, int32(Widthptr), obj.DUPOK|obj.RODATA) 234 } 235 236 // Do not reprocess funcsyms on next dumpglobls call. 237 funcsyms = nil 238 } 239 240 // addGCLocals adds gcargs and gclocals symbols to Ctxt.Data. 241 // It takes care not to add any duplicates. 242 // Though the object file format handles duplicates efficiently, 243 // storing only a single copy of the data, 244 // failure to remove these duplicates adds a few percent to object file size. 245 func addGCLocals() { 246 seen := make(map[string]bool) 247 for _, s := range Ctxt.Text { 248 if s.Func == nil { 249 continue 250 } 251 for _, gcsym := range []*obj.LSym{&s.Func.GCArgs, &s.Func.GCLocals} { 252 if seen[gcsym.Name] { 253 continue 254 } 255 Ctxt.Data = append(Ctxt.Data, gcsym) 256 seen[gcsym.Name] = true 257 } 258 } 259 } 260 261 func duintxx(s *obj.LSym, off int, v uint64, wid int) int { 262 if off&(wid-1) != 0 { 263 Fatalf("duintxxLSym: misaligned: v=%d wid=%d off=%d", v, wid, off) 264 } 265 s.WriteInt(Ctxt, int64(off), wid, int64(v)) 266 return off + wid 267 } 268 269 func duint8(s *obj.LSym, off int, v uint8) int { 270 return duintxx(s, off, uint64(v), 1) 271 } 272 273 func duint16(s *obj.LSym, off int, v uint16) int { 274 return duintxx(s, off, uint64(v), 2) 275 } 276 277 func duint32(s *obj.LSym, off int, v uint32) int { 278 return duintxx(s, off, uint64(v), 4) 279 } 280 281 func duintptr(s *obj.LSym, off int, v uint64) int { 282 return duintxx(s, off, v, Widthptr) 283 } 284 285 func dbvec(s *obj.LSym, off int, bv bvec) int { 286 // Runtime reads the bitmaps as byte arrays. Oblige. 287 for j := 0; int32(j) < bv.n; j += 8 { 288 word := bv.b[j/32] 289 off = duint8(s, off, uint8(word>>(uint(j)%32))) 290 } 291 return off 292 } 293 294 func stringsym(s string) (data *obj.LSym) { 295 var symname string 296 if len(s) > 100 { 297 // Huge strings are hashed to avoid long names in object files. 298 // Indulge in some paranoia by writing the length of s, too, 299 // as protection against length extension attacks. 300 h := sha256.New() 301 io.WriteString(h, s) 302 symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil)) 303 } else { 304 // Small strings get named directly by their contents. 305 symname = strconv.Quote(s) 306 } 307 308 const prefix = "go.string." 309 symdataname := prefix + symname 310 311 symdata := Ctxt.Lookup(symdataname) 312 313 if !symdata.SeenGlobl() { 314 // string data 315 off := dsname(symdata, 0, s) 316 ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL) 317 } 318 319 return symdata 320 } 321 322 var slicebytes_gen int 323 324 func slicebytes(nam *Node, s string, len int) { 325 slicebytes_gen++ 326 symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen) 327 sym := localpkg.Lookup(symname) 328 sym.Def = asTypesNode(newname(sym)) 329 330 lsym := sym.Linksym() 331 off := dsname(lsym, 0, s) 332 ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL) 333 334 if nam.Op != ONAME { 335 Fatalf("slicebytes %v", nam) 336 } 337 nsym := nam.Sym.Linksym() 338 off = int(nam.Xoffset) 339 off = dsymptr(nsym, off, lsym, 0) 340 off = duintptr(nsym, off, uint64(len)) 341 duintptr(nsym, off, uint64(len)) 342 } 343 344 func dsname(s *obj.LSym, off int, t string) int { 345 s.WriteString(Ctxt, int64(off), len(t), t) 346 return off + len(t) 347 } 348 349 func dsymptr(s *obj.LSym, off int, x *obj.LSym, xoff int) int { 350 off = int(Rnd(int64(off), int64(Widthptr))) 351 s.WriteAddr(Ctxt, int64(off), Widthptr, x, int64(xoff)) 352 off += Widthptr 353 return off 354 } 355 356 func dsymptrOff(s *obj.LSym, off int, x *obj.LSym, xoff int) int { 357 s.WriteOff(Ctxt, int64(off), x, int64(xoff)) 358 off += 4 359 return off 360 } 361 362 func dsymptrWeakOff(s *obj.LSym, off int, x *obj.LSym) int { 363 s.WriteWeakOff(Ctxt, int64(off), x, 0) 364 off += 4 365 return off 366 } 367 368 func gdata(nam *Node, nr *Node, wid int) { 369 if nam.Op != ONAME { 370 Fatalf("gdata nam op %v", nam.Op) 371 } 372 if nam.Sym == nil { 373 Fatalf("gdata nil nam sym") 374 } 375 s := nam.Sym.Linksym() 376 377 switch nr.Op { 378 case OLITERAL: 379 switch u := nr.Val().U.(type) { 380 case bool: 381 i := int64(obj.Bool2int(u)) 382 s.WriteInt(Ctxt, nam.Xoffset, wid, i) 383 384 case *Mpint: 385 s.WriteInt(Ctxt, nam.Xoffset, wid, u.Int64()) 386 387 case *Mpflt: 388 f := u.Float64() 389 switch nam.Type.Etype { 390 case TFLOAT32: 391 s.WriteFloat32(Ctxt, nam.Xoffset, float32(f)) 392 case TFLOAT64: 393 s.WriteFloat64(Ctxt, nam.Xoffset, f) 394 } 395 396 case *Mpcplx: 397 r := u.Real.Float64() 398 i := u.Imag.Float64() 399 switch nam.Type.Etype { 400 case TCOMPLEX64: 401 s.WriteFloat32(Ctxt, nam.Xoffset, float32(r)) 402 s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i)) 403 case TCOMPLEX128: 404 s.WriteFloat64(Ctxt, nam.Xoffset, r) 405 s.WriteFloat64(Ctxt, nam.Xoffset+8, i) 406 } 407 408 case string: 409 symdata := stringsym(u) 410 s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0) 411 s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthptr, int64(len(u))) 412 413 default: 414 Fatalf("gdata unhandled OLITERAL %v", nr) 415 } 416 417 case OADDR: 418 if nr.Left.Op != ONAME { 419 Fatalf("gdata ADDR left op %v", nr.Left.Op) 420 } 421 to := nr.Left 422 s.WriteAddr(Ctxt, nam.Xoffset, wid, to.Sym.Linksym(), to.Xoffset) 423 424 case ONAME: 425 if nr.Class() != PFUNC { 426 Fatalf("gdata NAME not PFUNC %d", nr.Class()) 427 } 428 s.WriteAddr(Ctxt, nam.Xoffset, wid, funcsym(nr.Sym).Linksym(), nr.Xoffset) 429 430 default: 431 Fatalf("gdata unhandled op %v %v\n", nr, nr.Op) 432 } 433 }