github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/cmd/ld/data.c (about) 1 // Inferno utils/8l/asm.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 // Data layout and relocation. 32 33 #include "l.h" 34 #include "../ld/lib.h" 35 #include "../ld/elf.h" 36 #include "../ld/macho.h" 37 #include "../ld/pe.h" 38 #include "../../runtime/mgc0.h" 39 40 void dynreloc(void); 41 42 /* 43 * divide-and-conquer list-link 44 * sort of LSym* structures. 45 * Used for the data block. 46 */ 47 int 48 datcmp(LSym *s1, LSym *s2) 49 { 50 if(s1->type != s2->type) 51 return (int)s1->type - (int)s2->type; 52 if(s1->size != s2->size) { 53 if(s1->size < s2->size) 54 return -1; 55 return +1; 56 } 57 return strcmp(s1->name, s2->name); 58 } 59 60 LSym* 61 listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off) 62 { 63 LSym *l1, *l2, *le; 64 #define NEXT(l) (*(LSym**)((char*)(l)+off)) 65 66 if(l == 0 || NEXT(l) == 0) 67 return l; 68 69 l1 = l; 70 l2 = l; 71 for(;;) { 72 l2 = NEXT(l2); 73 if(l2 == 0) 74 break; 75 l2 = NEXT(l2); 76 if(l2 == 0) 77 break; 78 l1 = NEXT(l1); 79 } 80 81 l2 = NEXT(l1); 82 NEXT(l1) = 0; 83 l1 = listsort(l, cmp, off); 84 l2 = listsort(l2, cmp, off); 85 86 /* set up lead element */ 87 if(cmp(l1, l2) < 0) { 88 l = l1; 89 l1 = NEXT(l1); 90 } else { 91 l = l2; 92 l2 = NEXT(l2); 93 } 94 le = l; 95 96 for(;;) { 97 if(l1 == 0) { 98 while(l2) { 99 NEXT(le) = l2; 100 le = l2; 101 l2 = NEXT(l2); 102 } 103 NEXT(le) = 0; 104 break; 105 } 106 if(l2 == 0) { 107 while(l1) { 108 NEXT(le) = l1; 109 le = l1; 110 l1 = NEXT(l1); 111 } 112 break; 113 } 114 if(cmp(l1, l2) < 0) { 115 NEXT(le) = l1; 116 le = l1; 117 l1 = NEXT(l1); 118 } else { 119 NEXT(le) = l2; 120 le = l2; 121 l2 = NEXT(l2); 122 } 123 } 124 NEXT(le) = 0; 125 return l; 126 127 #undef NEXT 128 } 129 130 void 131 relocsym(LSym *s) 132 { 133 Reloc *r; 134 LSym *rs; 135 int32 i, off, siz, fl; 136 vlong o; 137 uchar *cast; 138 139 ctxt->cursym = s; 140 for(r=s->r; r<s->r+s->nr; r++) { 141 r->done = 1; 142 off = r->off; 143 siz = r->siz; 144 if(off < 0 || off+siz > s->np) { 145 diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np); 146 continue; 147 } 148 if(r->sym != S && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) { 149 diag("%s: not defined", r->sym->name); 150 continue; 151 } 152 if(r->type >= 256) 153 continue; 154 if(r->siz == 0) // informational relocation - no work to do 155 continue; 156 157 // Solaris needs the ability to reference dynimport symbols. 158 if(HEADTYPE != Hsolaris && r->sym != S && r->sym->type == SDYNIMPORT) 159 diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type); 160 if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable) 161 diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); 162 163 // Android emulates runtime.tlsg as a regular variable. 164 if (r->type == R_TLS && strcmp(goos, "android") == 0) 165 r->type = R_ADDR; 166 167 switch(r->type) { 168 default: 169 o = 0; 170 if(archreloc(r, s, &o) < 0) 171 diag("unknown reloc %d", r->type); 172 break; 173 case R_TLS: 174 if(linkmode == LinkInternal && iself && thechar == '5') { 175 // On ELF ARM, the thread pointer is 8 bytes before 176 // the start of the thread-local data block, so add 8 177 // to the actual TLS offset (r->sym->value). 178 // This 8 seems to be a fundamental constant of 179 // ELF on ARM (or maybe Glibc on ARM); it is not 180 // related to the fact that our own TLS storage happens 181 // to take up 8 bytes. 182 o = 8 + r->sym->value; 183 break; 184 } 185 r->done = 0; 186 o = 0; 187 if(thechar != '6') 188 o = r->add; 189 break; 190 case R_TLS_LE: 191 if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { 192 r->done = 0; 193 r->sym = ctxt->tlsg; 194 r->xsym = ctxt->tlsg; 195 r->xadd = r->add; 196 o = 0; 197 if(thechar != '6') 198 o = r->add; 199 break; 200 } 201 o = ctxt->tlsoffset + r->add; 202 break; 203 204 case R_TLS_IE: 205 if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { 206 r->done = 0; 207 r->sym = ctxt->tlsg; 208 r->xsym = ctxt->tlsg; 209 r->xadd = r->add; 210 o = 0; 211 if(thechar != '6') 212 o = r->add; 213 break; 214 } 215 if(iself || ctxt->headtype == Hplan9) 216 o = ctxt->tlsoffset + r->add; 217 else if(ctxt->headtype == Hwindows) 218 o = r->add; 219 else 220 sysfatal("unexpected R_TLS_IE relocation for %s", headstr(ctxt->headtype)); 221 break; 222 case R_ADDR: 223 if(linkmode == LinkExternal && r->sym->type != SCONST) { 224 r->done = 0; 225 226 // set up addend for eventual relocation via outer symbol. 227 rs = r->sym; 228 r->xadd = r->add; 229 while(rs->outer != nil) { 230 r->xadd += symaddr(rs) - symaddr(rs->outer); 231 rs = rs->outer; 232 } 233 if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) 234 diag("missing section for %s", rs->name); 235 r->xsym = rs; 236 237 o = r->xadd; 238 if(iself) { 239 if(thechar == '6') 240 o = 0; 241 } else if(HEADTYPE == Hdarwin) { 242 if(rs->type != SHOSTOBJ) 243 o += symaddr(rs); 244 } else { 245 diag("unhandled pcrel relocation for %s", headstring); 246 } 247 break; 248 } 249 o = symaddr(r->sym) + r->add; 250 251 // On amd64, 4-byte offsets will be sign-extended, so it is impossible to 252 // access more than 2GB of static data; fail at link time is better than 253 // fail at runtime. See http://golang.org/issue/7980. 254 // Instead of special casing only amd64, we treat this as an error on all 255 // 64-bit architectures so as to be future-proof. 256 if((int32)o < 0 && PtrSize > 4 && siz == 4) { 257 diag("non-pc-relative relocation address is too big: %#llux", o); 258 errorexit(); 259 } 260 break; 261 case R_CALL: 262 case R_PCREL: 263 // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. 264 if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) { 265 r->done = 0; 266 267 // set up addend for eventual relocation via outer symbol. 268 rs = r->sym; 269 r->xadd = r->add; 270 while(rs->outer != nil) { 271 r->xadd += symaddr(rs) - symaddr(rs->outer); 272 rs = rs->outer; 273 } 274 r->xadd -= r->siz; // relative to address after the relocated chunk 275 if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) 276 diag("missing section for %s", rs->name); 277 r->xsym = rs; 278 279 o = r->xadd; 280 if(iself) { 281 if(thechar == '6') 282 o = 0; 283 } else if(HEADTYPE == Hdarwin) { 284 if(r->type == R_CALL) { 285 if(rs->type != SHOSTOBJ) 286 o += symaddr(rs) - rs->sect->vaddr; 287 o -= r->off; // relative to section offset, not symbol 288 } else { 289 o += r->siz; 290 } 291 } else { 292 diag("unhandled pcrel relocation for %s", headstring); 293 } 294 break; 295 } 296 o = 0; 297 if(r->sym) 298 o += symaddr(r->sym); 299 // NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c 300 // compiler. The expression s->value + r->off + r->siz is int32 + int32 + 301 // uchar, and Plan 9 8c incorrectly treats the expression as type uint32 302 // instead of int32, causing incorrect values when sign extended for adding 303 // to o. The bug only occurs on Plan 9, because this C program is compiled by 304 // the standard host compiler (gcc on most other systems). 305 o += r->add - (s->value + r->off + (int32)r->siz); 306 break; 307 case R_SIZE: 308 o = r->sym->size + r->add; 309 break; 310 } 311 //print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o); 312 switch(siz) { 313 default: 314 ctxt->cursym = s; 315 diag("bad reloc size %#ux for %s", siz, r->sym->name); 316 case 1: 317 // TODO(rsc): Remove. 318 s->p[off] = (int8)o; 319 break; 320 case 4: 321 if(r->type == R_PCREL || r->type == R_CALL) { 322 if(o != (int32)o) 323 diag("pc-relative relocation address is too big: %#llx", o); 324 } else { 325 if(o != (int32)o && o != (uint32)o) 326 diag("non-pc-relative relocation address is too big: %#llux", o); 327 } 328 fl = o; 329 cast = (uchar*)&fl; 330 for(i=0; i<4; i++) 331 s->p[off+i] = cast[inuxi4[i]]; 332 break; 333 case 8: 334 cast = (uchar*)&o; 335 for(i=0; i<8; i++) 336 s->p[off+i] = cast[inuxi8[i]]; 337 break; 338 } 339 } 340 } 341 342 void 343 reloc(void) 344 { 345 LSym *s; 346 347 if(debug['v']) 348 Bprint(&bso, "%5.2f reloc\n", cputime()); 349 Bflush(&bso); 350 351 for(s=ctxt->textp; s!=S; s=s->next) 352 relocsym(s); 353 for(s=datap; s!=S; s=s->next) 354 relocsym(s); 355 } 356 357 void 358 dynrelocsym(LSym *s) 359 { 360 Reloc *r; 361 362 if(HEADTYPE == Hwindows) { 363 LSym *rel, *targ; 364 365 rel = linklookup(ctxt, ".rel", 0); 366 if(s == rel) 367 return; 368 for(r=s->r; r<s->r+s->nr; r++) { 369 targ = r->sym; 370 if(targ == nil) 371 continue; 372 if(!targ->reachable) 373 diag("internal inconsistency: dynamic symbol %s is not reachable.", targ->name); 374 if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files. 375 targ->plt = rel->size; 376 r->sym = rel; 377 r->add = targ->plt; 378 379 // jmp *addr 380 if(thechar == '8') { 381 adduint8(ctxt, rel, 0xff); 382 adduint8(ctxt, rel, 0x25); 383 addaddr(ctxt, rel, targ); 384 adduint8(ctxt, rel, 0x90); 385 adduint8(ctxt, rel, 0x90); 386 } else { 387 adduint8(ctxt, rel, 0xff); 388 adduint8(ctxt, rel, 0x24); 389 adduint8(ctxt, rel, 0x25); 390 addaddrplus4(ctxt, rel, targ, 0); 391 adduint8(ctxt, rel, 0x90); 392 } 393 } else if(r->sym->plt >= 0) { 394 r->sym = rel; 395 r->add = targ->plt; 396 } 397 } 398 return; 399 } 400 401 for(r=s->r; r<s->r+s->nr; r++) { 402 if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) { 403 if(r->sym != S && !r->sym->reachable) 404 diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name); 405 adddynrel(s, r); 406 } 407 } 408 } 409 410 void 411 dynreloc(void) 412 { 413 LSym *s; 414 415 // -d suppresses dynamic loader format, so we may as well not 416 // compute these sections or mark their symbols as reachable. 417 if(debug['d'] && HEADTYPE != Hwindows) 418 return; 419 if(debug['v']) 420 Bprint(&bso, "%5.2f reloc\n", cputime()); 421 Bflush(&bso); 422 423 for(s=ctxt->textp; s!=S; s=s->next) 424 dynrelocsym(s); 425 for(s=datap; s!=S; s=s->next) 426 dynrelocsym(s); 427 if(iself) 428 elfdynhash(); 429 } 430 431 static void 432 blk(LSym *start, int64 addr, int64 size) 433 { 434 LSym *sym; 435 int64 eaddr; 436 uchar *p, *ep; 437 438 for(sym = start; sym != nil; sym = sym->next) 439 if(!(sym->type&SSUB) && sym->value >= addr) 440 break; 441 442 eaddr = addr+size; 443 for(; sym != nil; sym = sym->next) { 444 if(sym->type&SSUB) 445 continue; 446 if(sym->value >= eaddr) 447 break; 448 ctxt->cursym = sym; 449 if(sym->value < addr) { 450 diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); 451 errorexit(); 452 } 453 for(; addr < sym->value; addr++) 454 cput(0); 455 p = sym->p; 456 ep = p + sym->np; 457 while(p < ep) 458 cput(*p++); 459 addr += sym->np; 460 for(; addr < sym->value+sym->size; addr++) 461 cput(0); 462 if(addr != sym->value+sym->size) { 463 diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size); 464 errorexit(); 465 } 466 if(sym->value+sym->size >= eaddr) 467 break; 468 } 469 470 for(; addr < eaddr; addr++) 471 cput(0); 472 cflush(); 473 } 474 475 void 476 codeblk(int64 addr, int64 size) 477 { 478 LSym *sym; 479 int64 eaddr, n; 480 uchar *q; 481 482 if(debug['a']) 483 Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); 484 485 blk(ctxt->textp, addr, size); 486 487 /* again for printing */ 488 if(!debug['a']) 489 return; 490 491 for(sym = ctxt->textp; sym != nil; sym = sym->next) { 492 if(!sym->reachable) 493 continue; 494 if(sym->value >= addr) 495 break; 496 } 497 498 eaddr = addr + size; 499 for(; sym != nil; sym = sym->next) { 500 if(!sym->reachable) 501 continue; 502 if(sym->value >= eaddr) 503 break; 504 505 if(addr < sym->value) { 506 Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); 507 for(; addr < sym->value; addr++) 508 Bprint(&bso, " %.2ux", 0); 509 Bprint(&bso, "\n"); 510 } 511 512 Bprint(&bso, "%.6llux\t%-20s\n", (vlong)addr, sym->name); 513 n = sym->size; 514 q = sym->p; 515 516 while(n >= 16) { 517 Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q); 518 addr += 16; 519 q += 16; 520 n -= 16; 521 } 522 if(n > 0) 523 Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q); 524 addr += n; 525 } 526 527 if(addr < eaddr) { 528 Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); 529 for(; addr < eaddr; addr++) 530 Bprint(&bso, " %.2ux", 0); 531 } 532 Bflush(&bso); 533 } 534 535 void 536 datblk(int64 addr, int64 size) 537 { 538 LSym *sym; 539 int64 i, eaddr; 540 uchar *p, *ep; 541 char *typ, *rsname; 542 Reloc *r; 543 544 if(debug['a']) 545 Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); 546 547 blk(datap, addr, size); 548 549 /* again for printing */ 550 if(!debug['a']) 551 return; 552 553 for(sym = datap; sym != nil; sym = sym->next) 554 if(sym->value >= addr) 555 break; 556 557 eaddr = addr + size; 558 for(; sym != nil; sym = sym->next) { 559 if(sym->value >= eaddr) 560 break; 561 if(addr < sym->value) { 562 Bprint(&bso, "\t%.8ux| 00 ...\n", addr); 563 addr = sym->value; 564 } 565 Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr); 566 p = sym->p; 567 ep = p + sym->np; 568 while(p < ep) { 569 if(p > sym->p && (int)(p-sym->p)%16 == 0) 570 Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p))); 571 Bprint(&bso, " %.2ux", *p++); 572 } 573 addr += sym->np; 574 for(; addr < sym->value+sym->size; addr++) 575 Bprint(&bso, " %.2ux", 0); 576 Bprint(&bso, "\n"); 577 578 if(linkmode == LinkExternal) { 579 for(i=0; i<sym->nr; i++) { 580 r = &sym->r[i]; 581 rsname = ""; 582 if(r->sym) 583 rsname = r->sym->name; 584 typ = "?"; 585 switch(r->type) { 586 case R_ADDR: 587 typ = "addr"; 588 break; 589 case R_PCREL: 590 typ = "pcrel"; 591 break; 592 case R_CALL: 593 typ = "call"; 594 break; 595 } 596 Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n", 597 (uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add)); 598 } 599 } 600 } 601 602 if(addr < eaddr) 603 Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr); 604 Bprint(&bso, "\t%.8ux|\n", (uint)eaddr); 605 } 606 607 void 608 strnput(char *s, int n) 609 { 610 for(; n > 0 && *s; s++) { 611 cput(*s); 612 n--; 613 } 614 while(n > 0) { 615 cput(0); 616 n--; 617 } 618 } 619 620 void 621 addstrdata(char *name, char *value) 622 { 623 LSym *s, *sp; 624 char *p; 625 uchar reachable; 626 627 p = smprint("%s.str", name); 628 sp = linklookup(ctxt, p, 0); 629 free(p); 630 addstring(sp, value); 631 sp->type = SRODATA; 632 633 s = linklookup(ctxt, name, 0); 634 s->size = 0; 635 s->dupok = 1; 636 reachable = s->reachable; 637 addaddr(ctxt, s, sp); 638 adduintxx(ctxt, s, strlen(value), PtrSize); 639 640 // addstring, addaddr, etc., mark the symbols as reachable. 641 // In this case that is not necessarily true, so stick to what 642 // we know before entering this function. 643 s->reachable = reachable; 644 sp->reachable = reachable; 645 } 646 647 vlong 648 addstring(LSym *s, char *str) 649 { 650 int n; 651 int32 r; 652 653 if(s->type == 0) 654 s->type = SNOPTRDATA; 655 s->reachable = 1; 656 r = s->size; 657 n = strlen(str)+1; 658 if(strcmp(s->name, ".shstrtab") == 0) 659 elfsetstring(str, r); 660 symgrow(ctxt, s, r+n); 661 memmove(s->p+r, str, n); 662 s->size += n; 663 return r; 664 } 665 666 void 667 dosymtype(void) 668 { 669 LSym *s; 670 671 for(s = ctxt->allsym; s != nil; s = s->allsym) { 672 if(s->np > 0) { 673 if(s->type == SBSS) 674 s->type = SDATA; 675 if(s->type == SNOPTRBSS) 676 s->type = SNOPTRDATA; 677 } 678 } 679 } 680 681 static int32 682 symalign(LSym *s) 683 { 684 int32 align; 685 686 if(s->align != 0) 687 return s->align; 688 689 align = MaxAlign; 690 while(align > s->size && align > 1) 691 align >>= 1; 692 if(align < s->align) 693 align = s->align; 694 return align; 695 } 696 697 static vlong 698 aligndatsize(vlong datsize, LSym *s) 699 { 700 return rnd(datsize, symalign(s)); 701 } 702 703 // maxalign returns the maximum required alignment for 704 // the list of symbols s; the list stops when s->type exceeds type. 705 static int32 706 maxalign(LSym *s, int type) 707 { 708 int32 align, max; 709 710 max = 0; 711 for(; s != S && s->type <= type; s = s->next) { 712 align = symalign(s); 713 if(max < align) 714 max = align; 715 } 716 return max; 717 } 718 719 // Helper object for building GC type programs. 720 typedef struct ProgGen ProgGen; 721 struct ProgGen 722 { 723 LSym* s; 724 int32 datasize; 725 uint8 data[256/PointersPerByte]; 726 vlong pos; 727 }; 728 729 static void 730 proggeninit(ProgGen *g, LSym *s) 731 { 732 g->s = s; 733 g->datasize = 0; 734 g->pos = 0; 735 memset(g->data, 0, sizeof(g->data)); 736 } 737 738 static void 739 proggenemit(ProgGen *g, uint8 v) 740 { 741 adduint8(ctxt, g->s, v); 742 } 743 744 // Writes insData block from g->data. 745 static void 746 proggendataflush(ProgGen *g) 747 { 748 int32 i, s; 749 750 if(g->datasize == 0) 751 return; 752 proggenemit(g, insData); 753 proggenemit(g, g->datasize); 754 s = (g->datasize + PointersPerByte - 1)/PointersPerByte; 755 for(i = 0; i < s; i++) 756 proggenemit(g, g->data[i]); 757 g->datasize = 0; 758 memset(g->data, 0, sizeof(g->data)); 759 } 760 761 static void 762 proggendata(ProgGen *g, uint8 d) 763 { 764 g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer); 765 g->datasize++; 766 if(g->datasize == 255) 767 proggendataflush(g); 768 } 769 770 // Skip v bytes due to alignment, etc. 771 static void 772 proggenskip(ProgGen *g, vlong off, vlong v) 773 { 774 vlong i; 775 776 for(i = off; i < off+v; i++) { 777 if((i%PtrSize) == 0) 778 proggendata(g, BitsScalar); 779 } 780 } 781 782 // Emit insArray instruction. 783 static void 784 proggenarray(ProgGen *g, vlong len) 785 { 786 int32 i; 787 788 proggendataflush(g); 789 proggenemit(g, insArray); 790 for(i = 0; i < PtrSize; i++, len >>= 8) 791 proggenemit(g, len); 792 } 793 794 static void 795 proggenarrayend(ProgGen *g) 796 { 797 proggendataflush(g); 798 proggenemit(g, insArrayEnd); 799 } 800 801 static void 802 proggenfini(ProgGen *g, vlong size) 803 { 804 proggenskip(g, g->pos, size - g->pos); 805 proggendataflush(g); 806 proggenemit(g, insEnd); 807 } 808 809 810 // This function generates GC pointer info for global variables. 811 static void 812 proggenaddsym(ProgGen *g, LSym *s) 813 { 814 LSym *gcprog; 815 uint8 *mask; 816 vlong i, size; 817 818 if(s->size == 0) 819 return; 820 821 // Skip alignment hole from the previous symbol. 822 proggenskip(g, g->pos, s->value - g->pos); 823 g->pos += s->value - g->pos; 824 825 // The test for names beginning with . here is meant 826 // to keep .dynamic and .dynsym from turning up as 827 // conservative symbols. They should be marked SELFSECT 828 // and not SDATA, but sometimes that doesn't happen. 829 // Leave debugging the SDATA issue for the Go rewrite. 830 831 if(s->gotype == nil && s->size >= PtrSize && s->name[0] != '.') { 832 // conservative scan 833 diag("missing Go type information for global symbol: %s size %d", s->name, (int)s->size); 834 if((s->size%PtrSize) || (g->pos%PtrSize)) 835 diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld", 836 s->name, s->size, g->pos); 837 size = (s->size+PtrSize-1)/PtrSize*PtrSize; 838 if(size < 32*PtrSize) { 839 // Emit small symbols as data. 840 for(i = 0; i < size/PtrSize; i++) 841 proggendata(g, BitsPointer); 842 } else { 843 // Emit large symbols as array. 844 proggenarray(g, size/PtrSize); 845 proggendata(g, BitsPointer); 846 proggenarrayend(g); 847 } 848 g->pos = s->value + size; 849 } else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < PtrSize || s->name[0] == '.') { 850 // no scan 851 if(s->size < 32*PtrSize) { 852 // Emit small symbols as data. 853 // This case also handles unaligned and tiny symbols, so tread carefully. 854 for(i = s->value; i < s->value+s->size; i++) { 855 if((i%PtrSize) == 0) 856 proggendata(g, BitsScalar); 857 } 858 } else { 859 // Emit large symbols as array. 860 if((s->size%PtrSize) || (g->pos%PtrSize)) 861 diag("proggenaddsym: unaligned noscan symbol %s: size=%lld pos=%lld", 862 s->name, s->size, g->pos); 863 proggenarray(g, s->size/PtrSize); 864 proggendata(g, BitsScalar); 865 proggenarrayend(g); 866 } 867 g->pos = s->value + s->size; 868 } else if(decodetype_usegcprog(s->gotype)) { 869 // gc program, copy directly 870 proggendataflush(g); 871 gcprog = decodetype_gcprog(s->gotype); 872 size = decodetype_size(s->gotype); 873 if((size%PtrSize) || (g->pos%PtrSize)) 874 diag("proggenaddsym: unaligned gcprog symbol %s: size=%lld pos=%lld", 875 s->name, s->size, g->pos); 876 for(i = 0; i < gcprog->np-1; i++) 877 proggenemit(g, gcprog->p[i]); 878 g->pos = s->value + size; 879 } else { 880 // gc mask, it's small so emit as data 881 mask = decodetype_gcmask(s->gotype); 882 size = decodetype_size(s->gotype); 883 if((size%PtrSize) || (g->pos%PtrSize)) 884 diag("proggenaddsym: unaligned gcmask symbol %s: size=%lld pos=%lld", 885 s->name, s->size, g->pos); 886 for(i = 0; i < size; i += PtrSize) 887 proggendata(g, (mask[i/PtrSize/2]>>((i/PtrSize%2)*4+2))&BitsMask); 888 g->pos = s->value + size; 889 } 890 } 891 892 void 893 growdatsize(vlong *datsizep, LSym *s) 894 { 895 vlong datsize; 896 897 datsize = *datsizep; 898 if(s->size < 0) 899 diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size); 900 if(datsize + s->size < datsize) 901 diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size); 902 *datsizep = datsize + s->size; 903 } 904 905 void 906 dodata(void) 907 { 908 int32 n; 909 vlong datsize; 910 Section *sect; 911 Segment *segro; 912 LSym *s, *last, **l; 913 LSym *gcdata, *gcbss; 914 ProgGen gen; 915 916 if(debug['v']) 917 Bprint(&bso, "%5.2f dodata\n", cputime()); 918 Bflush(&bso); 919 920 last = nil; 921 datap = nil; 922 923 for(s=ctxt->allsym; s!=S; s=s->allsym) { 924 if(!s->reachable || s->special) 925 continue; 926 if(STEXT < s->type && s->type < SXREF) { 927 if(s->onlist) 928 sysfatal("symbol %s listed multiple times", s->name); 929 s->onlist = 1; 930 if(last == nil) 931 datap = s; 932 else 933 last->next = s; 934 s->next = nil; 935 last = s; 936 } 937 } 938 939 for(s = datap; s != nil; s = s->next) { 940 if(s->np > s->size) 941 diag("%s: initialize bounds (%lld < %d)", 942 s->name, (vlong)s->size, s->np); 943 } 944 945 946 /* 947 * now that we have the datap list, but before we start 948 * to assign addresses, record all the necessary 949 * dynamic relocations. these will grow the relocation 950 * symbol, which is itself data. 951 * 952 * on darwin, we need the symbol table numbers for dynreloc. 953 */ 954 if(HEADTYPE == Hdarwin) 955 machosymorder(); 956 dynreloc(); 957 958 /* some symbols may no longer belong in datap (Mach-O) */ 959 for(l=&datap; (s=*l) != nil; ) { 960 if(s->type <= STEXT || SXREF <= s->type) 961 *l = s->next; 962 else 963 l = &s->next; 964 } 965 *l = nil; 966 967 datap = listsort(datap, datcmp, offsetof(LSym, next)); 968 969 /* 970 * allocate sections. list is sorted by type, 971 * so we can just walk it for each piece we want to emit. 972 * segdata is processed before segtext, because we need 973 * to see all symbols in the .data and .bss sections in order 974 * to generate garbage collection information. 975 */ 976 977 /* begin segdata */ 978 979 /* skip symbols belonging to segtext */ 980 s = datap; 981 for(; s != nil && s->type < SELFSECT; s = s->next) 982 ; 983 984 /* writable ELF sections */ 985 datsize = 0; 986 for(; s != nil && s->type < SNOPTRDATA; s = s->next) { 987 sect = addsection(&segdata, s->name, 06); 988 sect->align = symalign(s); 989 datsize = rnd(datsize, sect->align); 990 sect->vaddr = datsize; 991 s->sect = sect; 992 s->type = SDATA; 993 s->value = datsize - sect->vaddr; 994 growdatsize(&datsize, s); 995 sect->len = datsize - sect->vaddr; 996 } 997 998 /* pointer-free data */ 999 sect = addsection(&segdata, ".noptrdata", 06); 1000 sect->align = maxalign(s, SINITARR-1); 1001 datsize = rnd(datsize, sect->align); 1002 sect->vaddr = datsize; 1003 linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect; 1004 linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect; 1005 for(; s != nil && s->type < SINITARR; s = s->next) { 1006 datsize = aligndatsize(datsize, s); 1007 s->sect = sect; 1008 s->type = SDATA; 1009 s->value = datsize - sect->vaddr; 1010 growdatsize(&datsize, s); 1011 } 1012 sect->len = datsize - sect->vaddr; 1013 1014 /* shared library initializer */ 1015 if(flag_shared) { 1016 sect = addsection(&segdata, ".init_array", 06); 1017 sect->align = maxalign(s, SINITARR); 1018 datsize = rnd(datsize, sect->align); 1019 sect->vaddr = datsize; 1020 for(; s != nil && s->type == SINITARR; s = s->next) { 1021 datsize = aligndatsize(datsize, s); 1022 s->sect = sect; 1023 s->value = datsize - sect->vaddr; 1024 growdatsize(&datsize, s); 1025 } 1026 sect->len = datsize - sect->vaddr; 1027 } 1028 1029 /* data */ 1030 sect = addsection(&segdata, ".data", 06); 1031 sect->align = maxalign(s, SBSS-1); 1032 datsize = rnd(datsize, sect->align); 1033 sect->vaddr = datsize; 1034 linklookup(ctxt, "runtime.data", 0)->sect = sect; 1035 linklookup(ctxt, "runtime.edata", 0)->sect = sect; 1036 gcdata = linklookup(ctxt, "runtime.gcdata", 0); 1037 proggeninit(&gen, gcdata); 1038 for(; s != nil && s->type < SBSS; s = s->next) { 1039 if(s->type == SINITARR) { 1040 ctxt->cursym = s; 1041 diag("unexpected symbol type %d", s->type); 1042 } 1043 s->sect = sect; 1044 s->type = SDATA; 1045 datsize = aligndatsize(datsize, s); 1046 s->value = datsize - sect->vaddr; 1047 proggenaddsym(&gen, s); // gc 1048 growdatsize(&datsize, s); 1049 } 1050 sect->len = datsize - sect->vaddr; 1051 proggenfini(&gen, sect->len); // gc 1052 1053 /* bss */ 1054 sect = addsection(&segdata, ".bss", 06); 1055 sect->align = maxalign(s, SNOPTRBSS-1); 1056 datsize = rnd(datsize, sect->align); 1057 sect->vaddr = datsize; 1058 linklookup(ctxt, "runtime.bss", 0)->sect = sect; 1059 linklookup(ctxt, "runtime.ebss", 0)->sect = sect; 1060 gcbss = linklookup(ctxt, "runtime.gcbss", 0); 1061 proggeninit(&gen, gcbss); 1062 for(; s != nil && s->type < SNOPTRBSS; s = s->next) { 1063 s->sect = sect; 1064 datsize = aligndatsize(datsize, s); 1065 s->value = datsize - sect->vaddr; 1066 proggenaddsym(&gen, s); // gc 1067 growdatsize(&datsize, s); 1068 } 1069 sect->len = datsize - sect->vaddr; 1070 proggenfini(&gen, sect->len); // gc 1071 1072 /* pointer-free bss */ 1073 sect = addsection(&segdata, ".noptrbss", 06); 1074 sect->align = maxalign(s, SNOPTRBSS); 1075 datsize = rnd(datsize, sect->align); 1076 sect->vaddr = datsize; 1077 linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect; 1078 linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect; 1079 for(; s != nil && s->type == SNOPTRBSS; s = s->next) { 1080 datsize = aligndatsize(datsize, s); 1081 s->sect = sect; 1082 s->value = datsize - sect->vaddr; 1083 growdatsize(&datsize, s); 1084 } 1085 sect->len = datsize - sect->vaddr; 1086 linklookup(ctxt, "runtime.end", 0)->sect = sect; 1087 1088 // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. 1089 if(datsize != (uint32)datsize) { 1090 diag("data or bss segment too large"); 1091 } 1092 1093 if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) { 1094 sect = addsection(&segdata, ".tbss", 06); 1095 sect->align = PtrSize; 1096 sect->vaddr = 0; 1097 datsize = 0; 1098 for(; s != nil && s->type == STLSBSS; s = s->next) { 1099 datsize = aligndatsize(datsize, s); 1100 s->sect = sect; 1101 s->value = datsize - sect->vaddr; 1102 growdatsize(&datsize, s); 1103 } 1104 sect->len = datsize; 1105 } else { 1106 // Might be internal linking but still using cgo. 1107 // In that case, the only possible STLSBSS symbol is runtime.tlsg. 1108 // Give it offset 0, because it's the only thing here. 1109 if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsg") == 0) { 1110 s->value = 0; 1111 s = s->next; 1112 } 1113 } 1114 1115 if(s != nil) { 1116 ctxt->cursym = nil; 1117 diag("unexpected symbol type %d for %s", s->type, s->name); 1118 } 1119 1120 /* 1121 * We finished data, begin read-only data. 1122 * Not all systems support a separate read-only non-executable data section. 1123 * ELF systems do. 1124 * OS X and Plan 9 do not. 1125 * Windows PE may, but if so we have not implemented it. 1126 * And if we're using external linking mode, the point is moot, 1127 * since it's not our decision; that code expects the sections in 1128 * segtext. 1129 */ 1130 if(iself && linkmode == LinkInternal) 1131 segro = &segrodata; 1132 else 1133 segro = &segtext; 1134 1135 s = datap; 1136 1137 datsize = 0; 1138 1139 /* read-only executable ELF, Mach-O sections */ 1140 for(; s != nil && s->type < STYPE; s = s->next) { 1141 sect = addsection(&segtext, s->name, 04); 1142 sect->align = symalign(s); 1143 datsize = rnd(datsize, sect->align); 1144 sect->vaddr = datsize; 1145 s->sect = sect; 1146 s->type = SRODATA; 1147 s->value = datsize - sect->vaddr; 1148 growdatsize(&datsize, s); 1149 sect->len = datsize - sect->vaddr; 1150 } 1151 1152 /* read-only data */ 1153 sect = addsection(segro, ".rodata", 04); 1154 sect->align = maxalign(s, STYPELINK-1); 1155 datsize = rnd(datsize, sect->align); 1156 sect->vaddr = 0; 1157 linklookup(ctxt, "runtime.rodata", 0)->sect = sect; 1158 linklookup(ctxt, "runtime.erodata", 0)->sect = sect; 1159 for(; s != nil && s->type < STYPELINK; s = s->next) { 1160 datsize = aligndatsize(datsize, s); 1161 s->sect = sect; 1162 s->type = SRODATA; 1163 s->value = datsize - sect->vaddr; 1164 growdatsize(&datsize, s); 1165 } 1166 sect->len = datsize - sect->vaddr; 1167 1168 /* typelink */ 1169 sect = addsection(segro, ".typelink", 04); 1170 sect->align = maxalign(s, STYPELINK); 1171 datsize = rnd(datsize, sect->align); 1172 sect->vaddr = datsize; 1173 linklookup(ctxt, "runtime.typelink", 0)->sect = sect; 1174 linklookup(ctxt, "runtime.etypelink", 0)->sect = sect; 1175 for(; s != nil && s->type == STYPELINK; s = s->next) { 1176 datsize = aligndatsize(datsize, s); 1177 s->sect = sect; 1178 s->type = SRODATA; 1179 s->value = datsize - sect->vaddr; 1180 growdatsize(&datsize, s); 1181 } 1182 sect->len = datsize - sect->vaddr; 1183 1184 /* gosymtab */ 1185 sect = addsection(segro, ".gosymtab", 04); 1186 sect->align = maxalign(s, SPCLNTAB-1); 1187 datsize = rnd(datsize, sect->align); 1188 sect->vaddr = datsize; 1189 linklookup(ctxt, "runtime.symtab", 0)->sect = sect; 1190 linklookup(ctxt, "runtime.esymtab", 0)->sect = sect; 1191 for(; s != nil && s->type < SPCLNTAB; s = s->next) { 1192 datsize = aligndatsize(datsize, s); 1193 s->sect = sect; 1194 s->type = SRODATA; 1195 s->value = datsize - sect->vaddr; 1196 growdatsize(&datsize, s); 1197 } 1198 sect->len = datsize - sect->vaddr; 1199 1200 /* gopclntab */ 1201 sect = addsection(segro, ".gopclntab", 04); 1202 sect->align = maxalign(s, SELFROSECT-1); 1203 datsize = rnd(datsize, sect->align); 1204 sect->vaddr = datsize; 1205 linklookup(ctxt, "runtime.pclntab", 0)->sect = sect; 1206 linklookup(ctxt, "runtime.epclntab", 0)->sect = sect; 1207 for(; s != nil && s->type < SELFROSECT; s = s->next) { 1208 datsize = aligndatsize(datsize, s); 1209 s->sect = sect; 1210 s->type = SRODATA; 1211 s->value = datsize - sect->vaddr; 1212 growdatsize(&datsize, s); 1213 } 1214 sect->len = datsize - sect->vaddr; 1215 1216 /* read-only ELF, Mach-O sections */ 1217 for(; s != nil && s->type < SELFSECT; s = s->next) { 1218 sect = addsection(segro, s->name, 04); 1219 sect->align = symalign(s); 1220 datsize = rnd(datsize, sect->align); 1221 sect->vaddr = datsize; 1222 s->sect = sect; 1223 s->type = SRODATA; 1224 s->value = datsize - sect->vaddr; 1225 growdatsize(&datsize, s); 1226 sect->len = datsize - sect->vaddr; 1227 } 1228 1229 // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. 1230 if(datsize != (uint32)datsize) { 1231 diag("read-only data segment too large"); 1232 } 1233 1234 /* number the sections */ 1235 n = 1; 1236 for(sect = segtext.sect; sect != nil; sect = sect->next) 1237 sect->extnum = n++; 1238 for(sect = segrodata.sect; sect != nil; sect = sect->next) 1239 sect->extnum = n++; 1240 for(sect = segdata.sect; sect != nil; sect = sect->next) 1241 sect->extnum = n++; 1242 } 1243 1244 // assign addresses to text 1245 void 1246 textaddress(void) 1247 { 1248 uvlong va; 1249 Section *sect; 1250 LSym *sym, *sub; 1251 1252 addsection(&segtext, ".text", 05); 1253 1254 // Assign PCs in text segment. 1255 // Could parallelize, by assigning to text 1256 // and then letting threads copy down, but probably not worth it. 1257 sect = segtext.sect; 1258 sect->align = funcalign; 1259 linklookup(ctxt, "runtime.text", 0)->sect = sect; 1260 linklookup(ctxt, "runtime.etext", 0)->sect = sect; 1261 va = INITTEXT; 1262 sect->vaddr = va; 1263 for(sym = ctxt->textp; sym != nil; sym = sym->next) { 1264 sym->sect = sect; 1265 if(sym->type & SSUB) 1266 continue; 1267 if(sym->align != 0) 1268 va = rnd(va, sym->align); 1269 else 1270 va = rnd(va, funcalign); 1271 sym->value = 0; 1272 for(sub = sym; sub != S; sub = sub->sub) 1273 sub->value += va; 1274 if(sym->size == 0 && sym->sub != S) 1275 ctxt->cursym = sym; 1276 va += sym->size; 1277 } 1278 sect->len = va - sect->vaddr; 1279 } 1280 1281 // assign addresses 1282 void 1283 address(void) 1284 { 1285 Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; 1286 Section *typelink; 1287 LSym *sym, *sub; 1288 uvlong va; 1289 vlong vlen; 1290 1291 va = INITTEXT; 1292 segtext.rwx = 05; 1293 segtext.vaddr = va; 1294 segtext.fileoff = HEADR; 1295 for(s=segtext.sect; s != nil; s=s->next) { 1296 va = rnd(va, s->align); 1297 s->vaddr = va; 1298 va += s->len; 1299 } 1300 segtext.len = va - INITTEXT; 1301 segtext.filelen = segtext.len; 1302 if(HEADTYPE == Hnacl) 1303 va += 32; // room for the "halt sled" 1304 1305 if(segrodata.sect != nil) { 1306 // align to page boundary so as not to mix 1307 // rodata and executable text. 1308 va = rnd(va, INITRND); 1309 1310 segrodata.rwx = 04; 1311 segrodata.vaddr = va; 1312 segrodata.fileoff = va - segtext.vaddr + segtext.fileoff; 1313 segrodata.filelen = 0; 1314 for(s=segrodata.sect; s != nil; s=s->next) { 1315 va = rnd(va, s->align); 1316 s->vaddr = va; 1317 va += s->len; 1318 } 1319 segrodata.len = va - segrodata.vaddr; 1320 segrodata.filelen = segrodata.len; 1321 } 1322 1323 va = rnd(va, INITRND); 1324 segdata.rwx = 06; 1325 segdata.vaddr = va; 1326 segdata.fileoff = va - segtext.vaddr + segtext.fileoff; 1327 segdata.filelen = 0; 1328 if(HEADTYPE == Hwindows) 1329 segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); 1330 if(HEADTYPE == Hplan9) 1331 segdata.fileoff = segtext.fileoff + segtext.filelen; 1332 data = nil; 1333 noptr = nil; 1334 bss = nil; 1335 noptrbss = nil; 1336 for(s=segdata.sect; s != nil; s=s->next) { 1337 vlen = s->len; 1338 if(s->next) 1339 vlen = s->next->vaddr - s->vaddr; 1340 s->vaddr = va; 1341 va += vlen; 1342 segdata.len = va - segdata.vaddr; 1343 if(strcmp(s->name, ".data") == 0) 1344 data = s; 1345 if(strcmp(s->name, ".noptrdata") == 0) 1346 noptr = s; 1347 if(strcmp(s->name, ".bss") == 0) 1348 bss = s; 1349 if(strcmp(s->name, ".noptrbss") == 0) 1350 noptrbss = s; 1351 } 1352 segdata.filelen = bss->vaddr - segdata.vaddr; 1353 1354 text = segtext.sect; 1355 if(segrodata.sect) 1356 rodata = segrodata.sect; 1357 else 1358 rodata = text->next; 1359 typelink = rodata->next; 1360 symtab = typelink->next; 1361 pclntab = symtab->next; 1362 1363 for(sym = datap; sym != nil; sym = sym->next) { 1364 ctxt->cursym = sym; 1365 if(sym->sect != nil) 1366 sym->value += sym->sect->vaddr; 1367 for(sub = sym->sub; sub != nil; sub = sub->sub) 1368 sub->value += sym->value; 1369 } 1370 1371 xdefine("runtime.text", STEXT, text->vaddr); 1372 xdefine("runtime.etext", STEXT, text->vaddr + text->len); 1373 xdefine("runtime.rodata", SRODATA, rodata->vaddr); 1374 xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->len); 1375 xdefine("runtime.typelink", SRODATA, typelink->vaddr); 1376 xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->len); 1377 1378 sym = linklookup(ctxt, "runtime.gcdata", 0); 1379 xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size); 1380 linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect; 1381 1382 sym = linklookup(ctxt, "runtime.gcbss", 0); 1383 xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size); 1384 linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect; 1385 1386 xdefine("runtime.symtab", SRODATA, symtab->vaddr); 1387 xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->len); 1388 xdefine("runtime.pclntab", SRODATA, pclntab->vaddr); 1389 xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->len); 1390 xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr); 1391 xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); 1392 xdefine("runtime.bss", SBSS, bss->vaddr); 1393 xdefine("runtime.ebss", SBSS, bss->vaddr + bss->len); 1394 xdefine("runtime.data", SDATA, data->vaddr); 1395 xdefine("runtime.edata", SDATA, data->vaddr + data->len); 1396 xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr); 1397 xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); 1398 xdefine("runtime.end", SBSS, segdata.vaddr + segdata.len); 1399 }