rsc.io/go@v0.0.0-20150416155037-e040fd465409/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 var outfile string 111 112 // The Go and C compilers, and the assembler, call writeobj to write 113 // out a Go object file. The linker does not call this; the linker 114 // does not write out object files. 115 func Writeobjdirect(ctxt *Link, b *Biobuf) { 116 var flag int 117 var s *LSym 118 var p *Prog 119 var plink *Prog 120 var a *Auto 121 122 // Build list of symbols, and assign instructions to lists. 123 // Ignore ctxt->plist boundaries. There are no guarantees there, 124 // and the C compilers and assemblers just use one big list. 125 var text *LSym 126 127 var curtext *LSym 128 var data *LSym 129 var etext *LSym 130 var edata *LSym 131 for pl := ctxt.Plist; pl != nil; pl = pl.Link { 132 for p = pl.Firstpc; p != nil; p = plink { 133 if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 { 134 fmt.Printf("obj: %v\n", p) 135 } 136 plink = p.Link 137 p.Link = nil 138 139 if p.As == AEND { 140 continue 141 } 142 143 if p.As == ATYPE { 144 // Assume each TYPE instruction describes 145 // a different local variable or parameter, 146 // so no dedup. 147 // Using only the TYPE instructions means 148 // that we discard location information about local variables 149 // in C and assembly functions; that information is inferred 150 // from ordinary references, because there are no TYPE 151 // instructions there. Without the type information, gdb can't 152 // use the locations, so we don't bother to save them. 153 // If something else could use them, we could arrange to 154 // preserve them. 155 if curtext == nil { 156 continue 157 } 158 a = new(Auto) 159 a.Asym = p.From.Sym 160 a.Aoffset = int32(p.From.Offset) 161 a.Name = int16(p.From.Name) 162 a.Gotype = p.From.Gotype 163 a.Link = curtext.Autom 164 curtext.Autom = a 165 continue 166 } 167 168 if p.As == AGLOBL { 169 s = p.From.Sym 170 tmp6 := s.Seenglobl 171 s.Seenglobl++ 172 if tmp6 != 0 { 173 fmt.Printf("duplicate %v\n", p) 174 } 175 if s.Onlist != 0 { 176 log.Fatalf("symbol %s listed multiple times", s.Name) 177 } 178 s.Onlist = 1 179 if data == nil { 180 data = s 181 } else { 182 edata.Next = s 183 } 184 s.Next = nil 185 s.Size = p.To.Offset 186 if s.Type == 0 || s.Type == SXREF { 187 s.Type = SBSS 188 } 189 flag = int(p.From3.Offset) 190 if flag&DUPOK != 0 { 191 s.Dupok = 1 192 } 193 if flag&RODATA != 0 { 194 s.Type = SRODATA 195 } else if flag&NOPTR != 0 { 196 s.Type = SNOPTRBSS 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.From3.Offset) 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 wrint(b, int64(s.Dupok)) 404 wrint(b, s.Size) 405 wrsym(b, s.Gotype) 406 wrdata(b, s.P) 407 408 wrint(b, int64(len(s.R))) 409 var r *Reloc 410 for i := 0; i < len(s.R); i++ { 411 r = &s.R[i] 412 wrint(b, int64(r.Off)) 413 wrint(b, int64(r.Siz)) 414 wrint(b, int64(r.Type)) 415 wrint(b, r.Add) 416 wrint(b, r.Xadd) 417 wrsym(b, r.Sym) 418 wrsym(b, r.Xsym) 419 } 420 421 if s.Type == STEXT { 422 wrint(b, int64(s.Args)) 423 wrint(b, int64(s.Locals)) 424 wrint(b, int64(s.Nosplit)) 425 wrint(b, int64(s.Leaf)|int64(s.Cfunc)<<1) 426 n := 0 427 for a := s.Autom; a != nil; a = a.Link { 428 n++ 429 } 430 wrint(b, int64(n)) 431 for a := s.Autom; a != nil; a = a.Link { 432 wrsym(b, a.Asym) 433 wrint(b, int64(a.Aoffset)) 434 if a.Name == NAME_AUTO { 435 wrint(b, A_AUTO) 436 } else if a.Name == NAME_PARAM { 437 wrint(b, A_PARAM) 438 } else { 439 log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name) 440 } 441 wrsym(b, a.Gotype) 442 } 443 444 pc := s.Pcln 445 wrdata(b, pc.Pcsp.P) 446 wrdata(b, pc.Pcfile.P) 447 wrdata(b, pc.Pcline.P) 448 wrint(b, int64(len(pc.Pcdata))) 449 for i := 0; i < len(pc.Pcdata); i++ { 450 wrdata(b, pc.Pcdata[i].P) 451 } 452 wrint(b, int64(len(pc.Funcdataoff))) 453 for i := 0; i < len(pc.Funcdataoff); i++ { 454 wrsym(b, pc.Funcdata[i]) 455 } 456 for i := 0; i < len(pc.Funcdataoff); i++ { 457 wrint(b, pc.Funcdataoff[i]) 458 } 459 wrint(b, int64(len(pc.File))) 460 for i := 0; i < len(pc.File); i++ { 461 wrpathsym(ctxt, b, pc.File[i]) 462 } 463 } 464 } 465 466 func wrint(b *Biobuf, sval int64) { 467 var v uint64 468 var buf [10]uint8 469 uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63)) 470 p := buf[:] 471 for v = uv; v >= 0x80; v >>= 7 { 472 p[0] = uint8(v | 0x80) 473 p = p[1:] 474 } 475 p[0] = uint8(v) 476 p = p[1:] 477 Bwrite(b, buf[:len(buf)-len(p)]) 478 } 479 480 func wrstring(b *Biobuf, s string) { 481 wrint(b, int64(len(s))) 482 b.w.WriteString(s) 483 } 484 485 // wrpath writes a path just like a string, but on windows, it 486 // translates '\\' to '/' in the process. 487 func wrpath(ctxt *Link, b *Biobuf, p string) { 488 wrstring(b, filepath.ToSlash(p)) 489 } 490 491 func wrdata(b *Biobuf, v []byte) { 492 wrint(b, int64(len(v))) 493 Bwrite(b, v) 494 } 495 496 func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) { 497 if s == nil { 498 wrint(b, 0) 499 wrint(b, 0) 500 return 501 } 502 503 wrpath(ctxt, b, s.Name) 504 wrint(b, int64(s.Version)) 505 } 506 507 func wrsym(b *Biobuf, s *LSym) { 508 if s == nil { 509 wrint(b, 0) 510 wrint(b, 0) 511 return 512 } 513 514 wrstring(b, s.Name) 515 wrint(b, int64(s.Version)) 516 } 517 518 var startmagic string = "\x00\x00go13ld" 519 520 var endmagic string = "\xff\xffgo13ld"