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