github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/liblink/objfile.c (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 and reading 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 #include <u.h> 102 #include <libc.h> 103 #include <bio.h> 104 #include <link.h> 105 #include "../cmd/ld/textflag.h" 106 #include "../runtime/funcdata.h" 107 108 static void writesym(Link*, Biobuf*, LSym*); 109 static void wrint(Biobuf*, int64); 110 static void wrstring(Biobuf*, char*); 111 static void wrpath(Link *, Biobuf*, char*); 112 static void wrdata(Biobuf*, void*, int); 113 static void wrsym(Biobuf*, LSym*); 114 static void wrpathsym(Link *ctxt, Biobuf *b, LSym *s); 115 116 static void readsym(Link*, Biobuf*, char*, char*); 117 static int64 rdint(Biobuf*); 118 static char *rdstring(Biobuf*); 119 static void rddata(Biobuf*, uchar**, int*); 120 static LSym *rdsym(Link*, Biobuf*, char*); 121 122 // The Go and C compilers, and the assembler, call writeobj to write 123 // out a Go object file. The linker does not call this; the linker 124 // does not write out object files. 125 void 126 writeobj(Link *ctxt, Biobuf *b) 127 { 128 int flag, found; 129 Hist *h; 130 LSym *s, *text, *etext, *curtext, *data, *edata; 131 Plist *pl; 132 Prog *p, *plink; 133 Auto *a; 134 135 // Build list of symbols, and assign instructions to lists. 136 // Ignore ctxt->plist boundaries. There are no guarantees there, 137 // and the C compilers and assemblers just use one big list. 138 text = nil; 139 curtext = nil; 140 data = nil; 141 etext = nil; 142 edata = nil; 143 for(pl = ctxt->plist; pl != nil; pl = pl->link) { 144 for(p = pl->firstpc; p != nil; p = plink) { 145 if(ctxt->debugasm && ctxt->debugvlog) 146 print("obj: %p %P\n", p, p); 147 plink = p->link; 148 p->link = nil; 149 150 if(p->as == ctxt->arch->AEND) 151 continue; 152 153 if(p->as == ctxt->arch->ATYPE) { 154 // Assume each TYPE instruction describes 155 // a different local variable or parameter, 156 // so no dedup. 157 // Using only the TYPE instructions means 158 // that we discard location information about local variables 159 // in C and assembly functions; that information is inferred 160 // from ordinary references, because there are no TYPE 161 // instructions there. Without the type information, gdb can't 162 // use the locations, so we don't bother to save them. 163 // If something else could use them, we could arrange to 164 // preserve them. 165 if(curtext == nil) 166 continue; 167 a = emallocz(sizeof *a); 168 a->asym = p->from.sym; 169 a->aoffset = p->from.offset; 170 a->type = ctxt->arch->symtype(&p->from); 171 a->gotype = p->from.gotype; 172 a->link = curtext->autom; 173 curtext->autom = a; 174 continue; 175 } 176 177 if(p->as == ctxt->arch->AGLOBL) { 178 s = p->from.sym; 179 if(s->seenglobl++) 180 print("duplicate %P\n", p); 181 if(s->onlist) 182 sysfatal("symbol %s listed multiple times", s->name); 183 s->onlist = 1; 184 if(data == nil) 185 data = s; 186 else 187 edata->next = s; 188 s->next = nil; 189 s->size = p->to.offset; 190 if(s->type == 0 || s->type == SXREF) 191 s->type = SBSS; 192 flag = ctxt->arch->textflag(p); 193 if(flag & DUPOK) 194 s->dupok = 1; 195 if(flag & RODATA) 196 s->type = SRODATA; 197 else if(flag & NOPTR) 198 s->type = SNOPTRBSS; 199 edata = s; 200 continue; 201 } 202 203 if(p->as == ctxt->arch->ADATA) { 204 savedata(ctxt, p->from.sym, p, "<input>"); 205 continue; 206 } 207 208 if(p->as == ctxt->arch->ATEXT) { 209 s = p->from.sym; 210 if(s == nil) { 211 // func _() { } 212 curtext = nil; 213 continue; 214 } 215 if(s->text != nil) 216 sysfatal("duplicate TEXT for %s", s->name); 217 if(s->onlist) 218 sysfatal("symbol %s listed multiple times", s->name); 219 s->onlist = 1; 220 if(text == nil) 221 text = s; 222 else 223 etext->next = s; 224 etext = s; 225 flag = ctxt->arch->textflag(p); 226 if(flag & DUPOK) 227 s->dupok = 1; 228 if(flag & NOSPLIT) 229 s->nosplit = 1; 230 s->next = nil; 231 s->type = STEXT; 232 s->text = p; 233 s->etext = p; 234 curtext = s; 235 continue; 236 } 237 238 if(p->as == ctxt->arch->AFUNCDATA) { 239 // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information. 240 if(curtext == nil) // func _() {} 241 continue; 242 if(strcmp(p->to.sym->name, "go_args_stackmap") == 0) { 243 if(p->from.type != ctxt->arch->D_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps) 244 ctxt->diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps"); 245 p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", curtext->name), curtext->version); 246 } 247 } 248 249 if(curtext == nil) 250 continue; 251 s = curtext; 252 s->etext->link = p; 253 s->etext = p; 254 } 255 } 256 257 // Add reference to Go arguments for C or assembly functions without them. 258 for(s = text; s != nil; s = s->next) { 259 if(strncmp(s->name, "\"\".", 3) != 0) 260 continue; 261 found = 0; 262 for(p = s->text; p != nil; p = p->link) { 263 if(p->as == ctxt->arch->AFUNCDATA && p->from.type == ctxt->arch->D_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) { 264 found = 1; 265 break; 266 } 267 } 268 if(!found) { 269 p = appendp(ctxt, s->text); 270 p->as = ctxt->arch->AFUNCDATA; 271 p->from.type = ctxt->arch->D_CONST; 272 p->from.offset = FUNCDATA_ArgsPointerMaps; 273 if(ctxt->arch->thechar == '6' || ctxt->arch->thechar == '8') 274 p->to.type = ctxt->arch->D_EXTERN; 275 else { 276 p->to.type = ctxt->arch->D_OREG; 277 p->to.name = ctxt->arch->D_EXTERN; 278 } 279 p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version); 280 } 281 } 282 283 // Turn functions into machine code images. 284 for(s = text; s != nil; s = s->next) { 285 mkfwd(s); 286 linkpatch(ctxt, s); 287 ctxt->arch->follow(ctxt, s); 288 ctxt->arch->addstacksplit(ctxt, s); 289 ctxt->arch->assemble(ctxt, s); 290 linkpcln(ctxt, s); 291 } 292 293 // Emit header. 294 Bputc(b, 0); 295 Bputc(b, 0); 296 Bprint(b, "go13ld"); 297 Bputc(b, 1); // version 298 299 // Emit autolib. 300 for(h = ctxt->hist; h != nil; h = h->link) 301 if(h->offset < 0) 302 wrstring(b, h->name); 303 wrstring(b, ""); 304 305 // Emit symbols. 306 for(s = text; s != nil; s = s->next) 307 writesym(ctxt, b, s); 308 for(s = data; s != nil; s = s->next) 309 writesym(ctxt, b, s); 310 311 // Emit footer. 312 Bputc(b, 0xff); 313 Bputc(b, 0xff); 314 Bprint(b, "go13ld"); 315 } 316 317 static void 318 writesym(Link *ctxt, Biobuf *b, LSym *s) 319 { 320 Reloc *r; 321 int i, j, c, n; 322 Pcln *pc; 323 Prog *p; 324 Auto *a; 325 char *name; 326 327 if(ctxt->debugasm) { 328 Bprint(ctxt->bso, "%s ", s->name); 329 if(s->version) 330 Bprint(ctxt->bso, "v=%d ", s->version); 331 if(s->type) 332 Bprint(ctxt->bso, "t=%d ", s->type); 333 if(s->dupok) 334 Bprint(ctxt->bso, "dupok "); 335 if(s->cfunc) 336 Bprint(ctxt->bso, "cfunc "); 337 if(s->nosplit) 338 Bprint(ctxt->bso, "nosplit "); 339 Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value); 340 if(s->type == STEXT) { 341 Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals); 342 if(s->leaf) 343 Bprint(ctxt->bso, " leaf"); 344 } 345 Bprint(ctxt->bso, "\n"); 346 for(p=s->text; p != nil; p = p->link) 347 Bprint(ctxt->bso, "\t%#06ux %P\n", (int)p->pc, p); 348 for(i=0; i<s->np; ) { 349 Bprint(ctxt->bso, "\t%#06ux", i); 350 for(j=i; j<i+16 && j<s->np; j++) 351 Bprint(ctxt->bso, " %02ux", s->p[j]); 352 for(; j<i+16; j++) 353 Bprint(ctxt->bso, " "); 354 Bprint(ctxt->bso, " "); 355 for(j=i; j<i+16 && j<s->np; j++) { 356 c = s->p[j]; 357 if(' ' <= c && c <= 0x7e) 358 Bprint(ctxt->bso, "%c", c); 359 else 360 Bprint(ctxt->bso, "."); 361 } 362 Bprint(ctxt->bso, "\n"); 363 i += 16; 364 } 365 for(i=0; i<s->nr; i++) { 366 r = &s->r[i]; 367 name = ""; 368 if(r->sym != nil) 369 name = r->sym->name; 370 if(ctxt->arch->thechar == '5' || ctxt->arch->thechar == '9') 371 Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%llux\n", (int)r->off, r->siz, r->type, name, (vlong)r->add); 372 else 373 Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add); 374 } 375 } 376 377 Bputc(b, 0xfe); 378 wrint(b, s->type); 379 wrstring(b, s->name); 380 wrint(b, s->version); 381 wrint(b, s->dupok); 382 wrint(b, s->size); 383 wrsym(b, s->gotype); 384 wrdata(b, s->p, s->np); 385 386 wrint(b, s->nr); 387 for(i=0; i<s->nr; i++) { 388 r = &s->r[i]; 389 wrint(b, r->off); 390 wrint(b, r->siz); 391 wrint(b, r->type); 392 wrint(b, r->add); 393 wrint(b, r->xadd); 394 wrsym(b, r->sym); 395 wrsym(b, r->xsym); 396 } 397 398 if(s->type == STEXT) { 399 wrint(b, s->args); 400 wrint(b, s->locals); 401 wrint(b, s->nosplit); 402 wrint(b, s->leaf | s->cfunc<<1); 403 n = 0; 404 for(a = s->autom; a != nil; a = a->link) 405 n++; 406 wrint(b, n); 407 for(a = s->autom; a != nil; a = a->link) { 408 wrsym(b, a->asym); 409 wrint(b, a->aoffset); 410 if(a->type == ctxt->arch->D_AUTO) 411 wrint(b, A_AUTO); 412 else if(a->type == ctxt->arch->D_PARAM) 413 wrint(b, A_PARAM); 414 else 415 sysfatal("%s: invalid local variable type %d", s->name, a->type); 416 wrsym(b, a->gotype); 417 } 418 419 pc = s->pcln; 420 wrdata(b, pc->pcsp.p, pc->pcsp.n); 421 wrdata(b, pc->pcfile.p, pc->pcfile.n); 422 wrdata(b, pc->pcline.p, pc->pcline.n); 423 wrint(b, pc->npcdata); 424 for(i=0; i<pc->npcdata; i++) 425 wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n); 426 wrint(b, pc->nfuncdata); 427 for(i=0; i<pc->nfuncdata; i++) 428 wrsym(b, pc->funcdata[i]); 429 for(i=0; i<pc->nfuncdata; i++) 430 wrint(b, pc->funcdataoff[i]); 431 wrint(b, pc->nfile); 432 for(i=0; i<pc->nfile; i++) 433 wrpathsym(ctxt, b, pc->file[i]); 434 } 435 } 436 437 static void 438 wrint(Biobuf *b, int64 sval) 439 { 440 uint64 uv, v; 441 uchar buf[10], *p; 442 443 uv = ((uint64)sval<<1) ^ (uint64)(int64)(sval>>63); 444 445 p = buf; 446 for(v = uv; v >= 0x80; v >>= 7) 447 *p++ = v | 0x80; 448 *p++ = v; 449 450 Bwrite(b, buf, p - buf); 451 } 452 453 static void 454 wrstring(Biobuf *b, char *s) 455 { 456 wrdata(b, s, strlen(s)); 457 } 458 459 // wrpath writes a path just like a string, but on windows, it 460 // translates '\\' to '/' in the process. 461 static void 462 wrpath(Link *ctxt, Biobuf *b, char *p) 463 { 464 int i, n; 465 if (!ctxt->windows || strchr(p, '\\') == nil) { 466 wrstring(b, p); 467 return; 468 } else { 469 n = strlen(p); 470 wrint(b, n); 471 for (i = 0; i < n; i++) 472 Bputc(b, p[i] == '\\' ? '/' : p[i]); 473 } 474 } 475 476 static void 477 wrdata(Biobuf *b, void *v, int n) 478 { 479 wrint(b, n); 480 Bwrite(b, v, n); 481 } 482 483 static void 484 wrpathsym(Link *ctxt, Biobuf *b, LSym *s) 485 { 486 if(s == nil) { 487 wrint(b, 0); 488 wrint(b, 0); 489 return; 490 } 491 wrpath(ctxt, b, s->name); 492 wrint(b, s->version); 493 } 494 495 static void 496 wrsym(Biobuf *b, LSym *s) 497 { 498 if(s == nil) { 499 wrint(b, 0); 500 wrint(b, 0); 501 return; 502 } 503 wrstring(b, s->name); 504 wrint(b, s->version); 505 } 506 507 static char startmagic[] = "\x00\x00go13ld"; 508 static char endmagic[] = "\xff\xffgo13ld"; 509 510 void 511 ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn) 512 { 513 int c; 514 uchar buf[8]; 515 int64 start; 516 char *lib; 517 518 start = Boffset(f); 519 ctxt->version++; 520 memset(buf, 0, sizeof buf); 521 Bread(f, buf, sizeof buf); 522 if(memcmp(buf, startmagic, sizeof buf) != 0) 523 sysfatal("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); 524 if((c = Bgetc(f)) != 1) 525 sysfatal("%s: invalid file version number %d", pn, c); 526 527 for(;;) { 528 lib = rdstring(f); 529 if(lib[0] == 0) 530 break; 531 addlib(ctxt, pkg, pn, lib); 532 } 533 534 for(;;) { 535 c = Bgetc(f); 536 Bungetc(f); 537 if(c == 0xff) 538 break; 539 readsym(ctxt, f, pkg, pn); 540 } 541 542 memset(buf, 0, sizeof buf); 543 Bread(f, buf, sizeof buf); 544 if(memcmp(buf, endmagic, sizeof buf) != 0) 545 sysfatal("%s: invalid file end", pn); 546 547 if(Boffset(f) != start+len) 548 sysfatal("%s: unexpected end at %lld, want %lld", pn, (vlong)Boffset(f), (vlong)(start+len)); 549 } 550 551 static void 552 readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn) 553 { 554 int i, j, c, t, v, n, ndata, nreloc, size, dupok; 555 static int ndup; 556 char *name; 557 uchar *data; 558 Reloc *r; 559 LSym *s, *dup, *typ; 560 Pcln *pc; 561 Auto *a; 562 563 if(Bgetc(f) != 0xfe) 564 sysfatal("readsym out of sync"); 565 t = rdint(f); 566 name = expandpkg(rdstring(f), pkg); 567 v = rdint(f); 568 if(v != 0 && v != 1) 569 sysfatal("invalid symbol version %d", v); 570 dupok = rdint(f); 571 dupok &= 1; 572 size = rdint(f); 573 typ = rdsym(ctxt, f, pkg); 574 rddata(f, &data, &ndata); 575 nreloc = rdint(f); 576 577 if(v != 0) 578 v = ctxt->version; 579 s = linklookup(ctxt, name, v); 580 dup = nil; 581 if(s->type != 0 && s->type != SXREF) { 582 if((t == SDATA || t == SBSS || t == SNOPTRBSS) && ndata == 0 && nreloc == 0) { 583 if(s->size < size) 584 s->size = size; 585 if(typ != nil && s->gotype == nil) 586 s->gotype = typ; 587 return; 588 } 589 if((s->type == SDATA || s->type == SBSS || s->type == SNOPTRBSS) && s->np == 0 && s->nr == 0) 590 goto overwrite; 591 if(s->type != SBSS && s->type != SNOPTRBSS && !dupok && !s->dupok) 592 sysfatal("duplicate symbol %s (types %d and %d) in %s and %s", s->name, s->type, t, s->file, pn); 593 if(s->np > 0) { 594 dup = s; 595 s = linknewsym(ctxt, ".dup", ndup++); // scratch 596 } 597 } 598 overwrite: 599 s->file = pkg; 600 s->dupok = dupok; 601 if(t == SXREF) 602 sysfatal("bad sxref"); 603 if(t == 0) 604 sysfatal("missing type for %s in %s", name, pn); 605 if(t == SBSS && (s->type == SRODATA || s->type == SNOPTRBSS)) 606 t = s->type; 607 s->type = t; 608 if(s->size < size) 609 s->size = size; 610 if(typ != nil) // if bss sym defined multiple times, take type from any one def 611 s->gotype = typ; 612 if(dup != nil && typ != nil) 613 dup->gotype = typ; 614 s->p = data; 615 s->np = ndata; 616 s->maxp = s->np; 617 if(nreloc > 0) { 618 s->r = emallocz(nreloc * sizeof s->r[0]); 619 s->nr = nreloc; 620 s->maxr = nreloc; 621 for(i=0; i<nreloc; i++) { 622 r = &s->r[i]; 623 r->off = rdint(f); 624 r->siz = rdint(f); 625 r->type = rdint(f); 626 r->add = rdint(f); 627 r->xadd = rdint(f); 628 r->sym = rdsym(ctxt, f, pkg); 629 r->xsym = rdsym(ctxt, f, pkg); 630 } 631 } 632 633 if(s->np > 0 && dup != nil && dup->np > 0 && strncmp(s->name, "gclocals·", 10) == 0) { 634 // content-addressed garbage collection liveness bitmap symbol. 635 // double check for hash collisions. 636 if(s->np != dup->np || memcmp(s->p, dup->p, s->np) != 0) 637 sysfatal("dupok hash collision for %s in %s and %s", s->name, s->file, pn); 638 } 639 640 if(s->type == STEXT) { 641 s->args = rdint(f); 642 s->locals = rdint(f); 643 s->nosplit = rdint(f); 644 v = rdint(f); 645 s->leaf = v&1; 646 s->cfunc = v&2; 647 n = rdint(f); 648 for(i=0; i<n; i++) { 649 a = emallocz(sizeof *a); 650 a->asym = rdsym(ctxt, f, pkg); 651 a->aoffset = rdint(f); 652 a->type = rdint(f); 653 a->gotype = rdsym(ctxt, f, pkg); 654 a->link = s->autom; 655 s->autom = a; 656 } 657 658 s->pcln = emallocz(sizeof *s->pcln); 659 pc = s->pcln; 660 rddata(f, &pc->pcsp.p, &pc->pcsp.n); 661 rddata(f, &pc->pcfile.p, &pc->pcfile.n); 662 rddata(f, &pc->pcline.p, &pc->pcline.n); 663 n = rdint(f); 664 pc->pcdata = emallocz(n * sizeof pc->pcdata[0]); 665 pc->npcdata = n; 666 for(i=0; i<n; i++) 667 rddata(f, &pc->pcdata[i].p, &pc->pcdata[i].n); 668 n = rdint(f); 669 pc->funcdata = emallocz(n * sizeof pc->funcdata[0]); 670 pc->funcdataoff = emallocz(n * sizeof pc->funcdataoff[0]); 671 pc->nfuncdata = n; 672 for(i=0; i<n; i++) 673 pc->funcdata[i] = rdsym(ctxt, f, pkg); 674 for(i=0; i<n; i++) 675 pc->funcdataoff[i] = rdint(f); 676 n = rdint(f); 677 pc->file = emallocz(n * sizeof pc->file[0]); 678 pc->nfile = n; 679 for(i=0; i<n; i++) 680 pc->file[i] = rdsym(ctxt, f, pkg); 681 682 if(dup == nil) { 683 if(s->onlist) 684 sysfatal("symbol %s listed multiple times", s->name); 685 s->onlist = 1; 686 if(ctxt->etextp) 687 ctxt->etextp->next = s; 688 else 689 ctxt->textp = s; 690 ctxt->etextp = s; 691 } 692 } 693 694 if(ctxt->debugasm) { 695 Bprint(ctxt->bso, "%s ", s->name); 696 if(s->version) 697 Bprint(ctxt->bso, "v=%d ", s->version); 698 if(s->type) 699 Bprint(ctxt->bso, "t=%d ", s->type); 700 if(s->dupok) 701 Bprint(ctxt->bso, "dupok "); 702 if(s->cfunc) 703 Bprint(ctxt->bso, "cfunc "); 704 if(s->nosplit) 705 Bprint(ctxt->bso, "nosplit "); 706 Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value); 707 if(s->type == STEXT) 708 Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals); 709 Bprint(ctxt->bso, "\n"); 710 for(i=0; i<s->np; ) { 711 Bprint(ctxt->bso, "\t%#06ux", i); 712 for(j=i; j<i+16 && j<s->np; j++) 713 Bprint(ctxt->bso, " %02ux", s->p[j]); 714 for(; j<i+16; j++) 715 Bprint(ctxt->bso, " "); 716 Bprint(ctxt->bso, " "); 717 for(j=i; j<i+16 && j<s->np; j++) { 718 c = s->p[j]; 719 if(' ' <= c && c <= 0x7e) 720 Bprint(ctxt->bso, "%c", c); 721 else 722 Bprint(ctxt->bso, "."); 723 } 724 Bprint(ctxt->bso, "\n"); 725 i += 16; 726 } 727 for(i=0; i<s->nr; i++) { 728 r = &s->r[i]; 729 Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, r->sym->name, (vlong)r->add); 730 } 731 } 732 } 733 734 static int64 735 rdint(Biobuf *f) 736 { 737 int c; 738 uint64 uv; 739 int shift; 740 741 uv = 0; 742 for(shift = 0;; shift += 7) { 743 if(shift >= 64) 744 sysfatal("corrupt input"); 745 c = Bgetc(f); 746 uv |= (uint64)(c & 0x7F) << shift; 747 if(!(c & 0x80)) 748 break; 749 } 750 751 return (int64)(uv>>1) ^ ((int64)((uint64)uv<<63)>>63); 752 } 753 754 static char* 755 rdstring(Biobuf *f) 756 { 757 int n; 758 char *p; 759 760 n = rdint(f); 761 p = emallocz(n+1); 762 Bread(f, p, n); 763 return p; 764 } 765 766 static void 767 rddata(Biobuf *f, uchar **pp, int *np) 768 { 769 *np = rdint(f); 770 *pp = emallocz(*np); 771 Bread(f, *pp, *np); 772 } 773 774 static LSym* 775 rdsym(Link *ctxt, Biobuf *f, char *pkg) 776 { 777 int n, v; 778 char *p; 779 LSym *s; 780 781 n = rdint(f); 782 if(n == 0) { 783 rdint(f); 784 return nil; 785 } 786 p = emallocz(n+1); 787 Bread(f, p, n); 788 v = rdint(f); 789 if(v != 0) 790 v = ctxt->version; 791 s = linklookup(ctxt, expandpkg(p, pkg), v); 792 793 if(v == 0 && s->name[0] == '$' && s->type == 0) { 794 if(strncmp(s->name, "$f32.", 5) == 0) { 795 int32 i32; 796 i32 = strtoul(s->name+5, nil, 16); 797 s->type = SRODATA; 798 adduint32(ctxt, s, i32); 799 s->reachable = 0; 800 } else if(strncmp(s->name, "$f64.", 5) == 0 || strncmp(s->name, "$i64.", 5) == 0) { 801 int64 i64; 802 i64 = strtoull(s->name+5, nil, 16); 803 s->type = SRODATA; 804 adduint64(ctxt, s, i64); 805 s->reachable = 0; 806 } 807 } 808 809 return s; 810 }