github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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 w.wr.Write(s.P) 132 } 133 134 // Symbols 135 for _, s := range ctxt.Text { 136 w.writeSym(s) 137 } 138 for _, s := range ctxt.Data { 139 w.writeSym(s) 140 } 141 142 // Magic footer 143 w.wr.WriteString("\xff\xffgo19ld") 144 } 145 146 // Symbols are prefixed so their content doesn't get confused with the magic footer. 147 const symPrefix = 0xfe 148 149 func (w *objWriter) writeRef(s *LSym, isPath bool) { 150 if s == nil || s.RefIdx != 0 { 151 return 152 } 153 var m map[string]int 154 if !s.Static() { 155 m = w.refIdx 156 } else { 157 m = w.vrefIdx 158 } 159 160 if idx := m[s.Name]; idx != 0 { 161 s.RefIdx = idx 162 return 163 } 164 w.wr.WriteByte(symPrefix) 165 if isPath { 166 w.writeString(filepath.ToSlash(s.Name)) 167 } else { 168 w.writeString(s.Name) 169 } 170 // Write "version". 171 if s.Static() { 172 w.writeInt(1) 173 } else { 174 w.writeInt(0) 175 } 176 w.nRefs++ 177 s.RefIdx = w.nRefs 178 m[s.Name] = w.nRefs 179 } 180 181 func (w *objWriter) writeRefs(s *LSym) { 182 w.writeRef(s, false) 183 w.writeRef(s.Gotype, false) 184 for i := range s.R { 185 w.writeRef(s.R[i].Sym, false) 186 } 187 188 if s.Type == objabi.STEXT { 189 for _, a := range s.Func.Autom { 190 w.writeRef(a.Asym, false) 191 w.writeRef(a.Gotype, false) 192 } 193 pc := &s.Func.Pcln 194 for _, d := range pc.Funcdata { 195 w.writeRef(d, false) 196 } 197 for _, f := range pc.File { 198 fsym := w.ctxt.Lookup(f) 199 w.writeRef(fsym, true) 200 } 201 for _, call := range pc.InlTree.nodes { 202 w.writeRef(call.Func, false) 203 f, _ := linkgetlineFromPos(w.ctxt, call.Pos) 204 fsym := w.ctxt.Lookup(f) 205 w.writeRef(fsym, true) 206 } 207 } 208 } 209 210 func (w *objWriter) writeSymDebug(s *LSym) { 211 ctxt := w.ctxt 212 fmt.Fprintf(ctxt.Bso, "%s ", s.Name) 213 if s.Type != 0 { 214 fmt.Fprintf(ctxt.Bso, "%v ", s.Type) 215 } 216 if s.Static() { 217 fmt.Fprint(ctxt.Bso, "static ") 218 } 219 if s.DuplicateOK() { 220 fmt.Fprintf(ctxt.Bso, "dupok ") 221 } 222 if s.CFunc() { 223 fmt.Fprintf(ctxt.Bso, "cfunc ") 224 } 225 if s.NoSplit() { 226 fmt.Fprintf(ctxt.Bso, "nosplit ") 227 } 228 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size) 229 if s.Type == objabi.STEXT { 230 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals)) 231 if s.Leaf() { 232 fmt.Fprintf(ctxt.Bso, " leaf") 233 } 234 } 235 fmt.Fprintf(ctxt.Bso, "\n") 236 if s.Type == objabi.STEXT { 237 for p := s.Func.Text; p != nil; p = p.Link { 238 fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p) 239 } 240 } 241 for i := 0; i < len(s.P); i += 16 { 242 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) 243 j := i 244 for j = i; j < i+16 && j < len(s.P); j++ { 245 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) 246 } 247 for ; j < i+16; j++ { 248 fmt.Fprintf(ctxt.Bso, " ") 249 } 250 fmt.Fprintf(ctxt.Bso, " ") 251 for j = i; j < i+16 && j < len(s.P); j++ { 252 c := int(s.P[j]) 253 if ' ' <= c && c <= 0x7e { 254 fmt.Fprintf(ctxt.Bso, "%c", c) 255 } else { 256 fmt.Fprintf(ctxt.Bso, ".") 257 } 258 } 259 260 fmt.Fprintf(ctxt.Bso, "\n") 261 } 262 263 sort.Sort(relocByOff(s.R)) // generate stable output 264 for _, r := range s.R { 265 name := "" 266 if r.Sym != nil { 267 name = r.Sym.Name 268 } else if r.Type == objabi.R_TLS_LE { 269 name = "TLS" 270 } 271 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) { 272 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add)) 273 } else { 274 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add) 275 } 276 } 277 } 278 279 func (w *objWriter) writeSym(s *LSym) { 280 ctxt := w.ctxt 281 if ctxt.Debugasm { 282 w.writeSymDebug(s) 283 } 284 285 w.wr.WriteByte(symPrefix) 286 w.writeInt(int64(s.Type)) 287 w.writeRefIndex(s) 288 flags := int64(0) 289 if s.DuplicateOK() { 290 flags |= 1 291 } 292 if s.Local() { 293 flags |= 1 << 1 294 } 295 if s.MakeTypelink() { 296 flags |= 1 << 2 297 } 298 w.writeInt(flags) 299 w.writeInt(s.Size) 300 w.writeRefIndex(s.Gotype) 301 w.writeInt(int64(len(s.P))) 302 303 w.writeInt(int64(len(s.R))) 304 var r *Reloc 305 for i := 0; i < len(s.R); i++ { 306 r = &s.R[i] 307 w.writeInt(int64(r.Off)) 308 w.writeInt(int64(r.Siz)) 309 w.writeInt(int64(r.Type)) 310 w.writeInt(r.Add) 311 w.writeRefIndex(r.Sym) 312 } 313 314 if s.Type != objabi.STEXT { 315 return 316 } 317 318 w.writeInt(int64(s.Func.Args)) 319 w.writeInt(int64(s.Func.Locals)) 320 if s.NoSplit() { 321 w.writeInt(1) 322 } else { 323 w.writeInt(0) 324 } 325 flags = int64(0) 326 if s.Leaf() { 327 flags |= 1 328 } 329 if s.CFunc() { 330 flags |= 1 << 1 331 } 332 if s.ReflectMethod() { 333 flags |= 1 << 2 334 } 335 w.writeInt(flags) 336 w.writeInt(int64(len(s.Func.Autom))) 337 for _, a := range s.Func.Autom { 338 w.writeRefIndex(a.Asym) 339 w.writeInt(int64(a.Aoffset)) 340 if a.Name == NAME_AUTO { 341 w.writeInt(objabi.A_AUTO) 342 } else if a.Name == NAME_PARAM { 343 w.writeInt(objabi.A_PARAM) 344 } else { 345 log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name) 346 } 347 w.writeRefIndex(a.Gotype) 348 } 349 350 pc := &s.Func.Pcln 351 w.writeInt(int64(len(pc.Pcsp.P))) 352 w.writeInt(int64(len(pc.Pcfile.P))) 353 w.writeInt(int64(len(pc.Pcline.P))) 354 w.writeInt(int64(len(pc.Pcinline.P))) 355 w.writeInt(int64(len(pc.Pcdata))) 356 for i := 0; i < len(pc.Pcdata); i++ { 357 w.writeInt(int64(len(pc.Pcdata[i].P))) 358 } 359 w.writeInt(int64(len(pc.Funcdataoff))) 360 for i := 0; i < len(pc.Funcdataoff); i++ { 361 w.writeRefIndex(pc.Funcdata[i]) 362 } 363 for i := 0; i < len(pc.Funcdataoff); i++ { 364 w.writeInt(pc.Funcdataoff[i]) 365 } 366 w.writeInt(int64(len(pc.File))) 367 for _, f := range pc.File { 368 fsym := ctxt.Lookup(f) 369 w.writeRefIndex(fsym) 370 } 371 w.writeInt(int64(len(pc.InlTree.nodes))) 372 for _, call := range pc.InlTree.nodes { 373 w.writeInt(int64(call.Parent)) 374 f, l := linkgetlineFromPos(w.ctxt, call.Pos) 375 fsym := ctxt.Lookup(f) 376 w.writeRefIndex(fsym) 377 w.writeInt(int64(l)) 378 w.writeRefIndex(call.Func) 379 } 380 } 381 382 func (w *objWriter) writeInt(sval int64) { 383 var v uint64 384 uv := (uint64(sval) << 1) ^ uint64(sval>>63) 385 p := w.varintbuf[:] 386 for v = uv; v >= 0x80; v >>= 7 { 387 p[0] = uint8(v | 0x80) 388 p = p[1:] 389 } 390 p[0] = uint8(v) 391 p = p[1:] 392 w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)]) 393 } 394 395 func (w *objWriter) writeString(s string) { 396 w.writeInt(int64(len(s))) 397 w.wr.WriteString(s) 398 } 399 400 func (w *objWriter) writeRefIndex(s *LSym) { 401 if s == nil { 402 w.writeInt(0) 403 return 404 } 405 if s.RefIdx == 0 { 406 log.Fatalln("writing an unreferenced symbol", s.Name) 407 } 408 w.writeInt(int64(s.RefIdx)) 409 } 410 411 // relocByOff sorts relocations by their offsets. 412 type relocByOff []Reloc 413 414 func (x relocByOff) Len() int { return len(x) } 415 func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off } 416 func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 417 418 // implement dwarf.Context 419 type dwCtxt struct{ *Link } 420 421 func (c dwCtxt) PtrSize() int { 422 return c.Arch.PtrSize 423 } 424 func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) { 425 ls := s.(*LSym) 426 ls.WriteInt(c.Link, ls.Size, size, i) 427 } 428 func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) { 429 ls := s.(*LSym) 430 ls.WriteBytes(c.Link, ls.Size, b) 431 } 432 func (c dwCtxt) AddString(s dwarf.Sym, v string) { 433 ls := s.(*LSym) 434 ls.WriteString(c.Link, ls.Size, len(v), v) 435 ls.WriteInt(c.Link, ls.Size, 1, 0) 436 } 437 func (c dwCtxt) SymValue(s dwarf.Sym) int64 { 438 return 0 439 } 440 func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) { 441 rsym := data.(*LSym) 442 ls := s.(*LSym) 443 size := c.PtrSize() 444 ls.WriteAddr(c.Link, ls.Size, size, rsym, value) 445 } 446 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { 447 ls := s.(*LSym) 448 rsym := t.(*LSym) 449 ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs) 450 r := &ls.R[len(ls.R)-1] 451 r.Type = objabi.R_DWARFREF 452 } 453 454 // dwarfSym returns the DWARF symbol for TEXT symbol. 455 func (ctxt *Link) dwarfSym(s *LSym) *LSym { 456 if s.Type != objabi.STEXT { 457 ctxt.Diag("dwarfSym of non-TEXT %v", s) 458 } 459 if s.Func.dwarfSym == nil { 460 s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name) 461 } 462 return s.Func.dwarfSym 463 } 464 465 // populateDWARF fills in the DWARF Debugging Information Entry for TEXT symbol s. 466 // The DWARF symbol must already have been initialized in InitTextSym. 467 func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) { 468 dsym := ctxt.dwarfSym(s) 469 if dsym.Size != 0 { 470 ctxt.Diag("makeFuncDebugEntry double process %v", s) 471 } 472 var vars []*dwarf.Var 473 if ctxt.DebugInfo != nil { 474 vars = ctxt.DebugInfo(s, curfn) 475 } 476 dwarf.PutFunc(dwCtxt{ctxt}, dsym, s.Name, !s.Static(), s, s.Size, vars) 477 }