github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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 // Originally, Go object files were Plan 9 object files, but no longer. 8 // Now they are more like standard object files, in that each symbol is defined 9 // by an associated memory image (bytes) and a list of relocations to apply 10 // during linking. We do not (yet?) use a standard file format, however. 11 // For now, the format is chosen to be as simple as possible to read and write. 12 // It may change for reasons of efficiency, or we may even switch to a 13 // standard file format if there are compelling benefits to doing so. 14 // See golang.org/s/go13linker for more background. 15 // 16 // The file format is: 17 // 18 // - magic header: "\x00\x00go13ld" 19 // - byte 1 - version number 20 // - sequence of strings giving dependencies (imported packages) 21 // - empty string (marks end of sequence) 22 // - sequence of defined symbols 23 // - byte 0xff (marks end of sequence) 24 // - magic footer: "\xff\xffgo13ld" 25 // 26 // All integers are stored in a zigzag varint format. 27 // See golang.org/s/go12symtab for a definition. 28 // 29 // Data blocks and strings are both stored as an integer 30 // followed by that many bytes. 31 // 32 // A symbol reference is a string name followed by a version. 33 // An empty name corresponds to a nil LSym* pointer. 34 // 35 // Each symbol is laid out as the following fields (taken from LSym*): 36 // 37 // - byte 0xfe (sanity check for synchronization) 38 // - type [int] 39 // - name [string] 40 // - version [int] 41 // - flags [int] 42 // 1 dupok 43 // - size [int] 44 // - gotype [symbol reference] 45 // - p [data block] 46 // - nr [int] 47 // - r [nr relocations, sorted by off] 48 // 49 // If type == STEXT, there are a few more fields: 50 // 51 // - args [int] 52 // - locals [int] 53 // - nosplit [int] 54 // - flags [int] 55 // 1 leaf 56 // 2 C function 57 // - nlocal [int] 58 // - local [nlocal automatics] 59 // - pcln [pcln table] 60 // 61 // Each relocation has the encoding: 62 // 63 // - off [int] 64 // - siz [int] 65 // - type [int] 66 // - add [int] 67 // - xadd [int] 68 // - sym [symbol reference] 69 // - xsym [symbol reference] 70 // 71 // Each local has the encoding: 72 // 73 // - asym [symbol reference] 74 // - offset [int] 75 // - type [int] 76 // - gotype [symbol reference] 77 // 78 // The pcln table has the encoding: 79 // 80 // - pcsp [data block] 81 // - pcfile [data block] 82 // - pcline [data block] 83 // - npcdata [int] 84 // - pcdata [npcdata data blocks] 85 // - nfuncdata [int] 86 // - funcdata [nfuncdata symbol references] 87 // - funcdatasym [nfuncdata ints] 88 // - nfile [int] 89 // - file [nfile symbol references] 90 // 91 // The file layout and meaning of type integers are architecture-independent. 92 // 93 // TODO(rsc): The file format is good for a first pass but needs work. 94 // - There are SymID in the object file that should really just be strings. 95 // - The actual symbol memory images are interlaced with the symbol 96 // metadata. They should be separated, to reduce the I/O required to 97 // load just the metadata. 98 // - The symbol references should be shortened, either with a symbol 99 // table or by using a simple backward index to an earlier mentioned symbol. 100 101 package obj 102 103 import ( 104 "fmt" 105 "log" 106 "path/filepath" 107 "strings" 108 ) 109 110 // The Go and C compilers, and the assembler, call writeobj to write 111 // out a Go object file. The linker does not call this; the linker 112 // does not write out object files. 113 func Writeobjdirect(ctxt *Link, b *Biobuf) { 114 var flag int 115 var s *LSym 116 var p *Prog 117 var plink *Prog 118 var a *Auto 119 120 // Build list of symbols, and assign instructions to lists. 121 // Ignore ctxt->plist boundaries. There are no guarantees there, 122 // and the C compilers and assemblers just use one big list. 123 var text *LSym 124 125 var curtext *LSym 126 var data *LSym 127 var etext *LSym 128 var edata *LSym 129 for pl := ctxt.Plist; pl != nil; pl = pl.Link { 130 for p = pl.Firstpc; p != nil; p = plink { 131 if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 { 132 fmt.Printf("obj: %v\n", p) 133 } 134 plink = p.Link 135 p.Link = nil 136 137 if p.As == AEND { 138 continue 139 } 140 141 if p.As == ATYPE { 142 // Assume each TYPE instruction describes 143 // a different local variable or parameter, 144 // so no dedup. 145 // Using only the TYPE instructions means 146 // that we discard location information about local variables 147 // in C and assembly functions; that information is inferred 148 // from ordinary references, because there are no TYPE 149 // instructions there. Without the type information, gdb can't 150 // use the locations, so we don't bother to save them. 151 // If something else could use them, we could arrange to 152 // preserve them. 153 if curtext == nil { 154 continue 155 } 156 a = new(Auto) 157 a.Asym = p.From.Sym 158 a.Aoffset = int32(p.From.Offset) 159 a.Name = int16(p.From.Name) 160 a.Gotype = p.From.Gotype 161 a.Link = curtext.Autom 162 curtext.Autom = a 163 continue 164 } 165 166 if p.As == AGLOBL { 167 s = p.From.Sym 168 tmp6 := s.Seenglobl 169 s.Seenglobl++ 170 if tmp6 != 0 { 171 fmt.Printf("duplicate %v\n", p) 172 } 173 if s.Onlist != 0 { 174 log.Fatalf("symbol %s listed multiple times", s.Name) 175 } 176 s.Onlist = 1 177 if data == nil { 178 data = s 179 } else { 180 edata.Next = s 181 } 182 s.Next = nil 183 s.Size = p.To.Offset 184 if s.Type == 0 || s.Type == SXREF { 185 s.Type = SBSS 186 } 187 flag = int(p.From3.Offset) 188 if flag&DUPOK != 0 { 189 s.Dupok = 1 190 } 191 if flag&RODATA != 0 { 192 s.Type = SRODATA 193 } else if flag&NOPTR != 0 { 194 s.Type = SNOPTRBSS 195 } else if flag&TLSBSS != 0 { 196 s.Type = STLSBSS 197 } 198 edata = s 199 continue 200 } 201 202 if p.As == ADATA { 203 savedata(ctxt, p.From.Sym, p, "<input>") 204 continue 205 } 206 207 if p.As == ATEXT { 208 s = p.From.Sym 209 if s == nil { 210 // func _() { } 211 curtext = nil 212 213 continue 214 } 215 216 if s.Text != nil { 217 log.Fatalf("duplicate TEXT for %s", s.Name) 218 } 219 if s.Onlist != 0 { 220 log.Fatalf("symbol %s listed multiple times", s.Name) 221 } 222 s.Onlist = 1 223 if text == nil { 224 text = s 225 } else { 226 etext.Next = s 227 } 228 etext = s 229 flag = int(p.From3Offset()) 230 if flag&DUPOK != 0 { 231 s.Dupok = 1 232 } 233 if flag&NOSPLIT != 0 { 234 s.Nosplit = 1 235 } 236 s.Next = nil 237 s.Type = STEXT 238 s.Text = p 239 s.Etext = p 240 curtext = s 241 continue 242 } 243 244 if p.As == AFUNCDATA { 245 // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information. 246 if curtext == nil { // func _() {} 247 continue 248 } 249 if p.To.Sym.Name == "go_args_stackmap" { 250 if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps { 251 ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps") 252 } 253 p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version)) 254 } 255 } 256 257 if curtext == nil { 258 continue 259 } 260 s = curtext 261 s.Etext.Link = p 262 s.Etext = p 263 } 264 } 265 266 // Add reference to Go arguments for C or assembly functions without them. 267 var found int 268 for s := text; s != nil; s = s.Next { 269 if !strings.HasPrefix(s.Name, "\"\".") { 270 continue 271 } 272 found = 0 273 for p = s.Text; p != nil; p = p.Link { 274 if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps { 275 found = 1 276 break 277 } 278 } 279 280 if found == 0 { 281 p = Appendp(ctxt, s.Text) 282 p.As = AFUNCDATA 283 p.From.Type = TYPE_CONST 284 p.From.Offset = FUNCDATA_ArgsPointerMaps 285 p.To.Type = TYPE_MEM 286 p.To.Name = NAME_EXTERN 287 p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version)) 288 } 289 } 290 291 // Turn functions into machine code images. 292 for s := text; s != nil; s = s.Next { 293 mkfwd(s) 294 linkpatch(ctxt, s) 295 ctxt.Arch.Follow(ctxt, s) 296 ctxt.Arch.Preprocess(ctxt, s) 297 ctxt.Arch.Assemble(ctxt, s) 298 linkpcln(ctxt, s) 299 } 300 301 // Emit header. 302 Bputc(b, 0) 303 304 Bputc(b, 0) 305 fmt.Fprintf(b, "go13ld") 306 Bputc(b, 1) // version 307 308 // Emit autolib. 309 for _, pkg := range ctxt.Imports { 310 wrstring(b, pkg) 311 } 312 wrstring(b, "") 313 314 // Emit symbols. 315 for s := text; s != nil; s = s.Next { 316 writesym(ctxt, b, s) 317 } 318 for s := data; s != nil; s = s.Next { 319 writesym(ctxt, b, s) 320 } 321 322 // Emit footer. 323 Bputc(b, 0xff) 324 325 Bputc(b, 0xff) 326 fmt.Fprintf(b, "go13ld") 327 } 328 329 func writesym(ctxt *Link, b *Biobuf, s *LSym) { 330 if ctxt.Debugasm != 0 { 331 fmt.Fprintf(ctxt.Bso, "%s ", s.Name) 332 if s.Version != 0 { 333 fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version) 334 } 335 if s.Type != 0 { 336 fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type) 337 } 338 if s.Dupok != 0 { 339 fmt.Fprintf(ctxt.Bso, "dupok ") 340 } 341 if s.Cfunc != 0 { 342 fmt.Fprintf(ctxt.Bso, "cfunc ") 343 } 344 if s.Nosplit != 0 { 345 fmt.Fprintf(ctxt.Bso, "nosplit ") 346 } 347 fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value)) 348 if s.Type == STEXT { 349 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals)) 350 if s.Leaf != 0 { 351 fmt.Fprintf(ctxt.Bso, " leaf") 352 } 353 } 354 355 fmt.Fprintf(ctxt.Bso, "\n") 356 for p := s.Text; p != nil; p = p.Link { 357 fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p) 358 } 359 var c int 360 var j int 361 for i := 0; i < len(s.P); { 362 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) 363 for j = i; j < i+16 && j < len(s.P); j++ { 364 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) 365 } 366 for ; j < i+16; j++ { 367 fmt.Fprintf(ctxt.Bso, " ") 368 } 369 fmt.Fprintf(ctxt.Bso, " ") 370 for j = i; j < i+16 && j < len(s.P); j++ { 371 c = int(s.P[j]) 372 if ' ' <= c && c <= 0x7e { 373 fmt.Fprintf(ctxt.Bso, "%c", c) 374 } else { 375 fmt.Fprintf(ctxt.Bso, ".") 376 } 377 } 378 379 fmt.Fprintf(ctxt.Bso, "\n") 380 i += 16 381 } 382 383 var r *Reloc 384 var name string 385 for i := 0; i < len(s.R); i++ { 386 r = &s.R[i] 387 name = "" 388 if r.Sym != nil { 389 name = r.Sym.Name 390 } 391 if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' { 392 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add))) 393 } else { 394 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add)) 395 } 396 } 397 } 398 399 Bputc(b, 0xfe) 400 wrint(b, int64(s.Type)) 401 wrstring(b, s.Name) 402 wrint(b, int64(s.Version)) 403 flags := int64(s.Dupok) 404 if s.Local { 405 flags |= 2 406 } 407 wrint(b, flags) 408 wrint(b, s.Size) 409 wrsym(b, s.Gotype) 410 wrdata(b, s.P) 411 412 wrint(b, int64(len(s.R))) 413 var r *Reloc 414 for i := 0; i < len(s.R); i++ { 415 r = &s.R[i] 416 wrint(b, int64(r.Off)) 417 wrint(b, int64(r.Siz)) 418 wrint(b, int64(r.Type)) 419 wrint(b, r.Add) 420 wrint(b, 0) // Xadd, ignored 421 wrsym(b, r.Sym) 422 wrsym(b, nil) // Xsym, ignored 423 } 424 425 if s.Type == STEXT { 426 wrint(b, int64(s.Args)) 427 wrint(b, int64(s.Locals)) 428 wrint(b, int64(s.Nosplit)) 429 wrint(b, int64(s.Leaf)|int64(s.Cfunc)<<1) 430 n := 0 431 for a := s.Autom; a != nil; a = a.Link { 432 n++ 433 } 434 wrint(b, int64(n)) 435 for a := s.Autom; a != nil; a = a.Link { 436 wrsym(b, a.Asym) 437 wrint(b, int64(a.Aoffset)) 438 if a.Name == NAME_AUTO { 439 wrint(b, A_AUTO) 440 } else if a.Name == NAME_PARAM { 441 wrint(b, A_PARAM) 442 } else { 443 log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name) 444 } 445 wrsym(b, a.Gotype) 446 } 447 448 pc := s.Pcln 449 wrdata(b, pc.Pcsp.P) 450 wrdata(b, pc.Pcfile.P) 451 wrdata(b, pc.Pcline.P) 452 wrint(b, int64(len(pc.Pcdata))) 453 for i := 0; i < len(pc.Pcdata); i++ { 454 wrdata(b, pc.Pcdata[i].P) 455 } 456 wrint(b, int64(len(pc.Funcdataoff))) 457 for i := 0; i < len(pc.Funcdataoff); i++ { 458 wrsym(b, pc.Funcdata[i]) 459 } 460 for i := 0; i < len(pc.Funcdataoff); i++ { 461 wrint(b, pc.Funcdataoff[i]) 462 } 463 wrint(b, int64(len(pc.File))) 464 for i := 0; i < len(pc.File); i++ { 465 wrpathsym(ctxt, b, pc.File[i]) 466 } 467 } 468 } 469 470 // Reusable buffer to avoid allocations. 471 // This buffer was responsible for 15% of gc's allocations. 472 var varintbuf [10]uint8 473 474 func wrint(b *Biobuf, sval int64) { 475 var v uint64 476 uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63)) 477 p := varintbuf[:] 478 for v = uv; v >= 0x80; v >>= 7 { 479 p[0] = uint8(v | 0x80) 480 p = p[1:] 481 } 482 p[0] = uint8(v) 483 p = p[1:] 484 b.Write(varintbuf[:len(varintbuf)-len(p)]) 485 } 486 487 func wrstring(b *Biobuf, s string) { 488 wrint(b, int64(len(s))) 489 b.w.WriteString(s) 490 } 491 492 // wrpath writes a path just like a string, but on windows, it 493 // translates '\\' to '/' in the process. 494 func wrpath(ctxt *Link, b *Biobuf, p string) { 495 wrstring(b, filepath.ToSlash(p)) 496 } 497 498 func wrdata(b *Biobuf, v []byte) { 499 wrint(b, int64(len(v))) 500 b.Write(v) 501 } 502 503 func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) { 504 if s == nil { 505 wrint(b, 0) 506 wrint(b, 0) 507 return 508 } 509 510 wrpath(ctxt, b, s.Name) 511 wrint(b, int64(s.Version)) 512 } 513 514 func wrsym(b *Biobuf, s *LSym) { 515 if s == nil { 516 wrint(b, 0) 517 wrint(b, 0) 518 return 519 } 520 521 wrstring(b, s.Name) 522 wrint(b, int64(s.Version)) 523 }