github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/internal/obj/objfile.go (about) 1 // Copyright 2013 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 // Writing of Go object files. 6 7 package obj 8 9 import ( 10 "bufio" 11 "cmd/internal/dwarf" 12 "cmd/internal/objabi" 13 "cmd/internal/sys" 14 "fmt" 15 "log" 16 "path/filepath" 17 "sort" 18 ) 19 20 // objWriter writes Go object files. 21 type objWriter struct { 22 wr *bufio.Writer 23 ctxt *Link 24 // Temporary buffer for zigzag int writing. 25 varintbuf [10]uint8 26 27 // Provide the index of a symbol reference by symbol name. 28 // One map for versioned symbols and one for unversioned symbols. 29 // Used for deduplicating the symbol reference list. 30 refIdx map[string]int 31 vrefIdx map[string]int 32 33 // Number of objects written of each type. 34 nRefs int 35 nData int 36 nReloc int 37 nPcdata int 38 nAutom int 39 nFuncdata int 40 nFile int 41 } 42 43 func (w *objWriter) addLengths(s *LSym) { 44 w.nData += len(s.P) 45 w.nReloc += len(s.R) 46 47 if s.Type != objabi.STEXT { 48 return 49 } 50 51 pc := &s.Func.Pcln 52 53 data := 0 54 data += len(pc.Pcsp.P) 55 data += len(pc.Pcfile.P) 56 data += len(pc.Pcline.P) 57 data += len(pc.Pcinline.P) 58 for i := 0; i < len(pc.Pcdata); i++ { 59 data += len(pc.Pcdata[i].P) 60 } 61 62 w.nData += data 63 w.nPcdata += len(pc.Pcdata) 64 65 w.nAutom += len(s.Func.Autom) 66 w.nFuncdata += len(pc.Funcdataoff) 67 w.nFile += len(pc.File) 68 } 69 70 func (w *objWriter) writeLengths() { 71 w.writeInt(int64(w.nData)) 72 w.writeInt(int64(w.nReloc)) 73 w.writeInt(int64(w.nPcdata)) 74 w.writeInt(int64(w.nAutom)) 75 w.writeInt(int64(w.nFuncdata)) 76 w.writeInt(int64(w.nFile)) 77 } 78 79 func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter { 80 return &objWriter{ 81 ctxt: ctxt, 82 wr: b, 83 vrefIdx: make(map[string]int), 84 refIdx: make(map[string]int), 85 } 86 } 87 88 func WriteObjFile(ctxt *Link, b *bufio.Writer) { 89 w := newObjWriter(ctxt, b) 90 91 // Magic header 92 w.wr.WriteString("\x00\x00go19ld") 93 94 // Version 95 w.wr.WriteByte(1) 96 97 // Autolib 98 for _, pkg := range ctxt.Imports { 99 w.writeString(pkg) 100 } 101 w.writeString("") 102 103 // Symbol references 104 for _, s := range ctxt.Text { 105 w.writeRefs(s) 106 w.addLengths(s) 107 } 108 for _, s := range ctxt.Data { 109 w.writeRefs(s) 110 w.addLengths(s) 111 } 112 // End symbol references 113 w.wr.WriteByte(0xff) 114 115 // Lengths 116 w.writeLengths() 117 118 // Data block 119 for _, s := range ctxt.Text { 120 w.wr.Write(s.P) 121 pc := &s.Func.Pcln 122 w.wr.Write(pc.Pcsp.P) 123 w.wr.Write(pc.Pcfile.P) 124 w.wr.Write(pc.Pcline.P) 125 w.wr.Write(pc.Pcinline.P) 126 for i := 0; i < len(pc.Pcdata); i++ { 127 w.wr.Write(pc.Pcdata[i].P) 128 } 129 } 130 for _, s := range ctxt.Data { 131 if len(s.P) > 0 { 132 switch s.Type { 133 case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS: 134 ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name) 135 } 136 } 137 w.wr.Write(s.P) 138 } 139 140 // Symbols 141 for _, s := range ctxt.Text { 142 w.writeSym(s) 143 } 144 for _, s := range ctxt.Data { 145 w.writeSym(s) 146 } 147 148 // Magic footer 149 w.wr.WriteString("\xff\xffgo19ld") 150 } 151 152 // Symbols are prefixed so their content doesn't get confused with the magic footer. 153 const symPrefix = 0xfe 154 155 func (w *objWriter) writeRef(s *LSym, isPath bool) { 156 if s == nil || s.RefIdx != 0 { 157 return 158 } 159 var m map[string]int 160 if !s.Static() { 161 m = w.refIdx 162 } else { 163 m = w.vrefIdx 164 } 165 166 if idx := m[s.Name]; idx != 0 { 167 s.RefIdx = idx 168 return 169 } 170 w.wr.WriteByte(symPrefix) 171 if isPath { 172 w.writeString(filepath.ToSlash(s.Name)) 173 } else { 174 w.writeString(s.Name) 175 } 176 // Write "version". 177 if s.Static() { 178 w.writeInt(1) 179 } else { 180 w.writeInt(0) 181 } 182 w.nRefs++ 183 s.RefIdx = w.nRefs 184 m[s.Name] = w.nRefs 185 } 186 187 func (w *objWriter) writeRefs(s *LSym) { 188 w.writeRef(s, false) 189 w.writeRef(s.Gotype, false) 190 for i := range s.R { 191 w.writeRef(s.R[i].Sym, false) 192 } 193 194 if s.Type == objabi.STEXT { 195 for _, a := range s.Func.Autom { 196 w.writeRef(a.Asym, false) 197 w.writeRef(a.Gotype, false) 198 } 199 pc := &s.Func.Pcln 200 for _, d := range pc.Funcdata { 201 w.writeRef(d, false) 202 } 203 for _, f := range pc.File { 204 fsym := w.ctxt.Lookup(f) 205 w.writeRef(fsym, true) 206 } 207 for _, call := range pc.InlTree.nodes { 208 w.writeRef(call.Func, false) 209 f, _ := linkgetlineFromPos(w.ctxt, call.Pos) 210 fsym := w.ctxt.Lookup(f) 211 w.writeRef(fsym, true) 212 } 213 } 214 } 215 216 func (w *objWriter) writeSymDebug(s *LSym) { 217 ctxt := w.ctxt 218 fmt.Fprintf(ctxt.Bso, "%s ", s.Name) 219 if s.Type != 0 { 220 fmt.Fprintf(ctxt.Bso, "%v ", s.Type) 221 } 222 if s.Static() { 223 fmt.Fprint(ctxt.Bso, "static ") 224 } 225 if s.DuplicateOK() { 226 fmt.Fprintf(ctxt.Bso, "dupok ") 227 } 228 if s.CFunc() { 229 fmt.Fprintf(ctxt.Bso, "cfunc ") 230 } 231 if s.NoSplit() { 232 fmt.Fprintf(ctxt.Bso, "nosplit ") 233 } 234 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size) 235 if s.Type == objabi.STEXT { 236 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals)) 237 if s.Leaf() { 238 fmt.Fprintf(ctxt.Bso, " leaf") 239 } 240 } 241 fmt.Fprintf(ctxt.Bso, "\n") 242 if s.Type == objabi.STEXT { 243 for p := s.Func.Text; p != nil; p = p.Link { 244 fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p) 245 } 246 } 247 for i := 0; i < len(s.P); i += 16 { 248 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) 249 j := i 250 for j = i; j < i+16 && j < len(s.P); j++ { 251 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) 252 } 253 for ; j < i+16; j++ { 254 fmt.Fprintf(ctxt.Bso, " ") 255 } 256 fmt.Fprintf(ctxt.Bso, " ") 257 for j = i; j < i+16 && j < len(s.P); j++ { 258 c := int(s.P[j]) 259 if ' ' <= c && c <= 0x7e { 260 fmt.Fprintf(ctxt.Bso, "%c", c) 261 } else { 262 fmt.Fprintf(ctxt.Bso, ".") 263 } 264 } 265 266 fmt.Fprintf(ctxt.Bso, "\n") 267 } 268 269 sort.Sort(relocByOff(s.R)) // generate stable output 270 for _, r := range s.R { 271 name := "" 272 if r.Sym != nil { 273 name = r.Sym.Name 274 } else if r.Type == objabi.R_TLS_LE { 275 name = "TLS" 276 } 277 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) { 278 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add)) 279 } else { 280 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add) 281 } 282 } 283 } 284 285 func (w *objWriter) writeSym(s *LSym) { 286 ctxt := w.ctxt 287 if ctxt.Debugasm { 288 w.writeSymDebug(s) 289 } 290 291 w.wr.WriteByte(symPrefix) 292 w.wr.WriteByte(byte(s.Type)) 293 w.writeRefIndex(s) 294 flags := int64(0) 295 if s.DuplicateOK() { 296 flags |= 1 297 } 298 if s.Local() { 299 flags |= 1 << 1 300 } 301 if s.MakeTypelink() { 302 flags |= 1 << 2 303 } 304 w.writeInt(flags) 305 w.writeInt(s.Size) 306 w.writeRefIndex(s.Gotype) 307 w.writeInt(int64(len(s.P))) 308 309 w.writeInt(int64(len(s.R))) 310 var r *Reloc 311 for i := 0; i < len(s.R); i++ { 312 r = &s.R[i] 313 w.writeInt(int64(r.Off)) 314 w.writeInt(int64(r.Siz)) 315 w.writeInt(int64(r.Type)) 316 w.writeInt(r.Add) 317 w.writeRefIndex(r.Sym) 318 } 319 320 if s.Type != objabi.STEXT { 321 return 322 } 323 324 w.writeInt(int64(s.Func.Args)) 325 w.writeInt(int64(s.Func.Locals)) 326 if s.NoSplit() { 327 w.writeInt(1) 328 } else { 329 w.writeInt(0) 330 } 331 flags = int64(0) 332 if s.Leaf() { 333 flags |= 1 334 } 335 if s.CFunc() { 336 flags |= 1 << 1 337 } 338 if s.ReflectMethod() { 339 flags |= 1 << 2 340 } 341 if ctxt.Flag_shared { 342 flags |= 1 << 3 343 } 344 w.writeInt(flags) 345 w.writeInt(int64(len(s.Func.Autom))) 346 for _, a := range s.Func.Autom { 347 w.writeRefIndex(a.Asym) 348 w.writeInt(int64(a.Aoffset)) 349 if a.Name == NAME_AUTO { 350 w.writeInt(objabi.A_AUTO) 351 } else if a.Name == NAME_PARAM { 352 w.writeInt(objabi.A_PARAM) 353 } else { 354 log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name) 355 } 356 w.writeRefIndex(a.Gotype) 357 } 358 359 pc := &s.Func.Pcln 360 w.writeInt(int64(len(pc.Pcsp.P))) 361 w.writeInt(int64(len(pc.Pcfile.P))) 362 w.writeInt(int64(len(pc.Pcline.P))) 363 w.writeInt(int64(len(pc.Pcinline.P))) 364 w.writeInt(int64(len(pc.Pcdata))) 365 for i := 0; i < len(pc.Pcdata); i++ { 366 w.writeInt(int64(len(pc.Pcdata[i].P))) 367 } 368 w.writeInt(int64(len(pc.Funcdataoff))) 369 for i := 0; i < len(pc.Funcdataoff); i++ { 370 w.writeRefIndex(pc.Funcdata[i]) 371 } 372 for i := 0; i < len(pc.Funcdataoff); i++ { 373 w.writeInt(pc.Funcdataoff[i]) 374 } 375 w.writeInt(int64(len(pc.File))) 376 for _, f := range pc.File { 377 fsym := ctxt.Lookup(f) 378 w.writeRefIndex(fsym) 379 } 380 w.writeInt(int64(len(pc.InlTree.nodes))) 381 for _, call := range pc.InlTree.nodes { 382 w.writeInt(int64(call.Parent)) 383 f, l := linkgetlineFromPos(w.ctxt, call.Pos) 384 fsym := ctxt.Lookup(f) 385 w.writeRefIndex(fsym) 386 w.writeInt(int64(l)) 387 w.writeRefIndex(call.Func) 388 } 389 } 390 391 func (w *objWriter) writeInt(sval int64) { 392 var v uint64 393 uv := (uint64(sval) << 1) ^ uint64(sval>>63) 394 p := w.varintbuf[:] 395 for v = uv; v >= 0x80; v >>= 7 { 396 p[0] = uint8(v | 0x80) 397 p = p[1:] 398 } 399 p[0] = uint8(v) 400 p = p[1:] 401 w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)]) 402 } 403 404 func (w *objWriter) writeString(s string) { 405 w.writeInt(int64(len(s))) 406 w.wr.WriteString(s) 407 } 408 409 func (w *objWriter) writeRefIndex(s *LSym) { 410 if s == nil { 411 w.writeInt(0) 412 return 413 } 414 if s.RefIdx == 0 { 415 log.Fatalln("writing an unreferenced symbol", s.Name) 416 } 417 w.writeInt(int64(s.RefIdx)) 418 } 419 420 // relocByOff sorts relocations by their offsets. 421 type relocByOff []Reloc 422 423 func (x relocByOff) Len() int { return len(x) } 424 func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off } 425 func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 426 427 // implement dwarf.Context 428 type dwCtxt struct{ *Link } 429 430 func (c dwCtxt) PtrSize() int { 431 return c.Arch.PtrSize 432 } 433 func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) { 434 ls := s.(*LSym) 435 ls.WriteInt(c.Link, ls.Size, size, i) 436 } 437 func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) { 438 ls := s.(*LSym) 439 ls.WriteBytes(c.Link, ls.Size, b) 440 } 441 func (c dwCtxt) AddString(s dwarf.Sym, v string) { 442 ls := s.(*LSym) 443 ls.WriteString(c.Link, ls.Size, len(v), v) 444 ls.WriteInt(c.Link, ls.Size, 1, 0) 445 } 446 func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) { 447 ls := s.(*LSym) 448 size := c.PtrSize() 449 if data != nil { 450 rsym := data.(*LSym) 451 ls.WriteAddr(c.Link, ls.Size, size, rsym, value) 452 } else { 453 ls.WriteInt(c.Link, ls.Size, size, value) 454 } 455 } 456 func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) { 457 ls := s.(*LSym) 458 rsym := data.(*LSym) 459 ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value) 460 } 461 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { 462 ls := s.(*LSym) 463 rsym := t.(*LSym) 464 ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs) 465 r := &ls.R[len(ls.R)-1] 466 r.Type = objabi.R_DWARFSECREF 467 } 468 func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) { 469 ls := s.(*LSym) 470 rsym := f.(*LSym) 471 ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0) 472 r := &ls.R[len(ls.R)-1] 473 r.Type = objabi.R_DWARFFILEREF 474 } 475 476 // dwarfSym returns the DWARF symbols for TEXT symbol. 477 func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym *LSym) { 478 if s.Type != objabi.STEXT { 479 ctxt.Diag("dwarfSym of non-TEXT %v", s) 480 } 481 if s.Func.dwarfInfoSym == nil { 482 s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name) 483 if ctxt.Flag_locationlists { 484 s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name) 485 } 486 s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name) 487 } 488 return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym 489 } 490 491 func (s *LSym) Len() int64 { 492 return s.Size 493 } 494 495 // fileSymbol returns a symbol corresponding to the source file of the 496 // first instruction (prog) of the specified function. This will 497 // presumably be the file in which the function is defined. 498 func (ctxt *Link) fileSymbol(fn *LSym) *LSym { 499 p := fn.Func.Text 500 if p != nil { 501 f, _ := linkgetlineFromPos(ctxt, p.Pos) 502 fsym := ctxt.Lookup(f) 503 return fsym 504 } 505 return nil 506 } 507 508 // populateDWARF fills in the DWARF Debugging Information Entries for TEXT symbol s. 509 // The DWARFs symbol must already have been initialized in InitTextSym. 510 func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) { 511 info, loc, ranges := ctxt.dwarfSym(s) 512 if info.Size != 0 { 513 ctxt.Diag("makeFuncDebugEntry double process %v", s) 514 } 515 var scopes []dwarf.Scope 516 if ctxt.DebugInfo != nil { 517 scopes = ctxt.DebugInfo(s, curfn) 518 } 519 520 fs := ctxt.fileSymbol(s) 521 err := dwarf.PutFunc(dwCtxt{ctxt}, info, loc, ranges, fs, s.Name, !s.Static(), s, s.Size, scopes) 522 if err != nil { 523 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 524 } 525 } 526 527 // DwarfIntConst creates a link symbol for an integer constant with the 528 // given name, type and value. 529 func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) { 530 if myimportpath == "" { 531 return 532 } 533 s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) { 534 s.Type = objabi.SDWARFINFO 535 ctxt.Data = append(ctxt.Data, s) 536 }) 537 dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val) 538 }