github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/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 if(sym->value < addr) { 449 diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); 450 errorexit(); 451 } 452 ctxt->cursym = sym; 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 } 467 468 for(; addr < eaddr; addr++) 469 cput(0); 470 cflush(); 471 } 472 473 void 474 codeblk(int64 addr, int64 size) 475 { 476 LSym *sym; 477 int64 eaddr, n; 478 uchar *q; 479 480 if(debug['a']) 481 Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); 482 483 blk(ctxt->textp, addr, size); 484 485 /* again for printing */ 486 if(!debug['a']) 487 return; 488 489 for(sym = ctxt->textp; sym != nil; sym = sym->next) { 490 if(!sym->reachable) 491 continue; 492 if(sym->value >= addr) 493 break; 494 } 495 496 eaddr = addr + size; 497 for(; sym != nil; sym = sym->next) { 498 if(!sym->reachable) 499 continue; 500 if(sym->value >= eaddr) 501 break; 502 503 if(addr < sym->value) { 504 Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); 505 for(; addr < sym->value; addr++) 506 Bprint(&bso, " %.2ux", 0); 507 Bprint(&bso, "\n"); 508 } 509 510 Bprint(&bso, "%.6llux\t%-20s\n", (vlong)addr, sym->name); 511 n = sym->size; 512 q = sym->p; 513 514 while(n >= 16) { 515 Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q); 516 addr += 16; 517 q += 16; 518 n -= 16; 519 } 520 if(n > 0) 521 Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q); 522 addr += n; 523 } 524 525 if(addr < eaddr) { 526 Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); 527 for(; addr < eaddr; addr++) 528 Bprint(&bso, " %.2ux", 0); 529 } 530 Bflush(&bso); 531 } 532 533 void 534 datblk(int64 addr, int64 size) 535 { 536 LSym *sym; 537 int64 i, eaddr; 538 uchar *p, *ep; 539 char *typ, *rsname; 540 Reloc *r; 541 542 if(debug['a']) 543 Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); 544 545 blk(datap, addr, size); 546 547 /* again for printing */ 548 if(!debug['a']) 549 return; 550 551 for(sym = datap; sym != nil; sym = sym->next) 552 if(sym->value >= addr) 553 break; 554 555 eaddr = addr + size; 556 for(; sym != nil; sym = sym->next) { 557 if(sym->value >= eaddr) 558 break; 559 if(addr < sym->value) { 560 Bprint(&bso, "\t%.8ux| 00 ...\n", addr); 561 addr = sym->value; 562 } 563 Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr); 564 p = sym->p; 565 ep = p + sym->np; 566 while(p < ep) { 567 if(p > sym->p && (int)(p-sym->p)%16 == 0) 568 Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p))); 569 Bprint(&bso, " %.2ux", *p++); 570 } 571 addr += sym->np; 572 for(; addr < sym->value+sym->size; addr++) 573 Bprint(&bso, " %.2ux", 0); 574 Bprint(&bso, "\n"); 575 576 if(linkmode == LinkExternal) { 577 for(i=0; i<sym->nr; i++) { 578 r = &sym->r[i]; 579 rsname = ""; 580 if(r->sym) 581 rsname = r->sym->name; 582 typ = "?"; 583 switch(r->type) { 584 case R_ADDR: 585 typ = "addr"; 586 break; 587 case R_PCREL: 588 typ = "pcrel"; 589 break; 590 case R_CALL: 591 typ = "call"; 592 break; 593 } 594 Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n", 595 (uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add)); 596 } 597 } 598 } 599 600 if(addr < eaddr) 601 Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr); 602 Bprint(&bso, "\t%.8ux|\n", (uint)eaddr); 603 } 604 605 void 606 strnput(char *s, int n) 607 { 608 for(; n > 0 && *s; s++) { 609 cput(*s); 610 n--; 611 } 612 while(n > 0) { 613 cput(0); 614 n--; 615 } 616 } 617 618 void 619 addstrdata(char *name, char *value) 620 { 621 LSym *s, *sp; 622 char *p; 623 uchar reachable; 624 625 p = smprint("%s.str", name); 626 sp = linklookup(ctxt, p, 0); 627 free(p); 628 addstring(sp, value); 629 sp->type = SRODATA; 630 631 s = linklookup(ctxt, name, 0); 632 s->size = 0; 633 s->dupok = 1; 634 reachable = s->reachable; 635 addaddr(ctxt, s, sp); 636 adduintxx(ctxt, s, strlen(value), PtrSize); 637 638 // addstring, addaddr, etc., mark the symbols as reachable. 639 // In this case that is not necessarily true, so stick to what 640 // we know before entering this function. 641 s->reachable = reachable; 642 sp->reachable = reachable; 643 } 644 645 vlong 646 addstring(LSym *s, char *str) 647 { 648 int n; 649 int32 r; 650 651 if(s->type == 0) 652 s->type = SNOPTRDATA; 653 s->reachable = 1; 654 r = s->size; 655 n = strlen(str)+1; 656 if(strcmp(s->name, ".shstrtab") == 0) 657 elfsetstring(str, r); 658 symgrow(ctxt, s, r+n); 659 memmove(s->p+r, str, n); 660 s->size += n; 661 return r; 662 } 663 664 void 665 dosymtype(void) 666 { 667 LSym *s; 668 669 for(s = ctxt->allsym; s != nil; s = s->allsym) { 670 if(s->np > 0) { 671 if(s->type == SBSS) 672 s->type = SDATA; 673 if(s->type == SNOPTRBSS) 674 s->type = SNOPTRDATA; 675 } 676 } 677 } 678 679 static int32 680 symalign(LSym *s) 681 { 682 int32 align; 683 684 if(s->align != 0) 685 return s->align; 686 687 align = MaxAlign; 688 while(align > s->size && align > 1) 689 align >>= 1; 690 if(align < s->align) 691 align = s->align; 692 return align; 693 } 694 695 static vlong 696 aligndatsize(vlong datsize, LSym *s) 697 { 698 return rnd(datsize, symalign(s)); 699 } 700 701 // maxalign returns the maximum required alignment for 702 // the list of symbols s; the list stops when s->type exceeds type. 703 static int32 704 maxalign(LSym *s, int type) 705 { 706 int32 align, max; 707 708 max = 0; 709 for(; s != S && s->type <= type; s = s->next) { 710 align = symalign(s); 711 if(max < align) 712 max = align; 713 } 714 return max; 715 } 716 717 // Helper object for building GC type programs. 718 typedef struct ProgGen ProgGen; 719 struct ProgGen 720 { 721 LSym* s; 722 int32 datasize; 723 uint8 data[256/PointersPerByte]; 724 vlong pos; 725 }; 726 727 static void 728 proggeninit(ProgGen *g, LSym *s) 729 { 730 g->s = s; 731 g->datasize = 0; 732 g->pos = 0; 733 memset(g->data, 0, sizeof(g->data)); 734 } 735 736 static void 737 proggenemit(ProgGen *g, uint8 v) 738 { 739 adduint8(ctxt, g->s, v); 740 } 741 742 // Writes insData block from g->data. 743 static void 744 proggendataflush(ProgGen *g) 745 { 746 int32 i, s; 747 748 if(g->datasize == 0) 749 return; 750 proggenemit(g, insData); 751 proggenemit(g, g->datasize); 752 s = (g->datasize + PointersPerByte - 1)/PointersPerByte; 753 for(i = 0; i < s; i++) 754 proggenemit(g, g->data[i]); 755 g->datasize = 0; 756 memset(g->data, 0, sizeof(g->data)); 757 } 758 759 static void 760 proggendata(ProgGen *g, uint8 d) 761 { 762 g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer); 763 g->datasize++; 764 if(g->datasize == 255) 765 proggendataflush(g); 766 } 767 768 // Skip v bytes due to alignment, etc. 769 static void 770 proggenskip(ProgGen *g, vlong off, vlong v) 771 { 772 vlong i; 773 774 for(i = off; i < off+v; i++) { 775 if((i%PtrSize) == 0) 776 proggendata(g, BitsScalar); 777 } 778 } 779 780 // Emit insArray instruction. 781 static void 782 proggenarray(ProgGen *g, vlong len) 783 { 784 int32 i; 785 786 proggendataflush(g); 787 proggenemit(g, insArray); 788 for(i = 0; i < PtrSize; i++, len >>= 8) 789 proggenemit(g, len); 790 } 791 792 static void 793 proggenarrayend(ProgGen *g) 794 { 795 proggendataflush(g); 796 proggenemit(g, insArrayEnd); 797 } 798 799 static void 800 proggenfini(ProgGen *g, vlong size) 801 { 802 proggenskip(g, g->pos, size - g->pos); 803 proggendataflush(g); 804 proggenemit(g, insEnd); 805 } 806 807 808 // This function generates GC pointer info for global variables. 809 static void 810 proggenaddsym(ProgGen *g, LSym *s) 811 { 812 LSym *gcprog; 813 uint8 *mask; 814 vlong i, size; 815 816 if(s->size == 0) 817 return; 818 819 // Skip alignment hole from the previous symbol. 820 proggenskip(g, g->pos, s->value - g->pos); 821 g->pos += s->value - g->pos; 822 823 // The test for names beginning with . here is meant 824 // to keep .dynamic and .dynsym from turning up as 825 // conservative symbols. They should be marked SELFSECT 826 // and not SDATA, but sometimes that doesn't happen. 827 // Leave debugging the SDATA issue for the Go rewrite. 828 829 if(s->gotype == nil && s->size >= PtrSize && s->name[0] != '.') { 830 // conservative scan 831 diag("missing Go type information for global symbol: %s size %d", s->name, (int)s->size); 832 if((s->size%PtrSize) || (g->pos%PtrSize)) 833 diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld", 834 s->name, s->size, g->pos); 835 size = (s->size+PtrSize-1)/PtrSize*PtrSize; 836 if(size < 32*PtrSize) { 837 // Emit small symbols as data. 838 for(i = 0; i < size/PtrSize; i++) 839 proggendata(g, BitsPointer); 840 } else { 841 // Emit large symbols as array. 842 proggenarray(g, size/PtrSize); 843 proggendata(g, BitsPointer); 844 proggenarrayend(g); 845 } 846 g->pos = s->value + size; 847 } else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < PtrSize || s->name[0] == '.') { 848 // no scan 849 if(s->size < 32*PtrSize) { 850 // Emit small symbols as data. 851 // This case also handles unaligned and tiny symbols, so tread carefully. 852 for(i = s->value; i < s->value+s->size; i++) { 853 if((i%PtrSize) == 0) 854 proggendata(g, BitsScalar); 855 } 856 } else { 857 // Emit large symbols as array. 858 if((s->size%PtrSize) || (g->pos%PtrSize)) 859 diag("proggenaddsym: unaligned noscan symbol %s: size=%lld pos=%lld", 860 s->name, s->size, g->pos); 861 proggenarray(g, s->size/PtrSize); 862 proggendata(g, BitsScalar); 863 proggenarrayend(g); 864 } 865 g->pos = s->value + s->size; 866 } else if(decodetype_usegcprog(s->gotype)) { 867 // gc program, copy directly 868 proggendataflush(g); 869 gcprog = decodetype_gcprog(s->gotype); 870 size = decodetype_size(s->gotype); 871 if((size%PtrSize) || (g->pos%PtrSize)) 872 diag("proggenaddsym: unaligned gcprog symbol %s: size=%lld pos=%lld", 873 s->name, s->size, g->pos); 874 for(i = 0; i < gcprog->np-1; i++) 875 proggenemit(g, gcprog->p[i]); 876 g->pos = s->value + size; 877 } else { 878 // gc mask, it's small so emit as data 879 mask = decodetype_gcmask(s->gotype); 880 size = decodetype_size(s->gotype); 881 if((size%PtrSize) || (g->pos%PtrSize)) 882 diag("proggenaddsym: unaligned gcmask symbol %s: size=%lld pos=%lld", 883 s->name, s->size, g->pos); 884 for(i = 0; i < size; i += PtrSize) 885 proggendata(g, (mask[i/PtrSize/2]>>((i/PtrSize%2)*4+2))&BitsMask); 886 g->pos = s->value + size; 887 } 888 } 889 890 void 891 growdatsize(vlong *datsizep, LSym *s) 892 { 893 vlong datsize; 894 895 datsize = *datsizep; 896 if(s->size < 0) 897 diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size); 898 if(datsize + s->size < datsize) 899 diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size); 900 *datsizep = datsize + s->size; 901 } 902 903 void 904 dodata(void) 905 { 906 int32 n; 907 vlong datsize; 908 Section *sect; 909 Segment *segro; 910 LSym *s, *last, **l; 911 LSym *gcdata, *gcbss; 912 ProgGen gen; 913 914 if(debug['v']) 915 Bprint(&bso, "%5.2f dodata\n", cputime()); 916 Bflush(&bso); 917 918 last = nil; 919 datap = nil; 920 921 for(s=ctxt->allsym; s!=S; s=s->allsym) { 922 if(!s->reachable || s->special) 923 continue; 924 if(STEXT < s->type && s->type < SXREF) { 925 if(s->onlist) 926 sysfatal("symbol %s listed multiple times", s->name); 927 s->onlist = 1; 928 if(last == nil) 929 datap = s; 930 else 931 last->next = s; 932 s->next = nil; 933 last = s; 934 } 935 } 936 937 for(s = datap; s != nil; s = s->next) { 938 if(s->np > s->size) 939 diag("%s: initialize bounds (%lld < %d)", 940 s->name, (vlong)s->size, s->np); 941 } 942 943 944 /* 945 * now that we have the datap list, but before we start 946 * to assign addresses, record all the necessary 947 * dynamic relocations. these will grow the relocation 948 * symbol, which is itself data. 949 * 950 * on darwin, we need the symbol table numbers for dynreloc. 951 */ 952 if(HEADTYPE == Hdarwin) 953 machosymorder(); 954 dynreloc(); 955 956 /* some symbols may no longer belong in datap (Mach-O) */ 957 for(l=&datap; (s=*l) != nil; ) { 958 if(s->type <= STEXT || SXREF <= s->type) 959 *l = s->next; 960 else 961 l = &s->next; 962 } 963 *l = nil; 964 965 datap = listsort(datap, datcmp, offsetof(LSym, next)); 966 967 /* 968 * allocate sections. list is sorted by type, 969 * so we can just walk it for each piece we want to emit. 970 * segdata is processed before segtext, because we need 971 * to see all symbols in the .data and .bss sections in order 972 * to generate garbage collection information. 973 */ 974 975 /* begin segdata */ 976 977 /* skip symbols belonging to segtext */ 978 s = datap; 979 for(; s != nil && s->type < SELFSECT; s = s->next) 980 ; 981 982 /* writable ELF sections */ 983 datsize = 0; 984 for(; s != nil && s->type < SNOPTRDATA; s = s->next) { 985 sect = addsection(&segdata, s->name, 06); 986 sect->align = symalign(s); 987 datsize = rnd(datsize, sect->align); 988 sect->vaddr = datsize; 989 s->sect = sect; 990 s->type = SDATA; 991 s->value = datsize - sect->vaddr; 992 growdatsize(&datsize, s); 993 sect->len = datsize - sect->vaddr; 994 } 995 996 /* pointer-free data */ 997 sect = addsection(&segdata, ".noptrdata", 06); 998 sect->align = maxalign(s, SINITARR-1); 999 datsize = rnd(datsize, sect->align); 1000 sect->vaddr = datsize; 1001 linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect; 1002 linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect; 1003 for(; s != nil && s->type < SINITARR; s = s->next) { 1004 datsize = aligndatsize(datsize, s); 1005 s->sect = sect; 1006 s->type = SDATA; 1007 s->value = datsize - sect->vaddr; 1008 growdatsize(&datsize, s); 1009 } 1010 sect->len = datsize - sect->vaddr; 1011 1012 /* shared library initializer */ 1013 if(flag_shared) { 1014 sect = addsection(&segdata, ".init_array", 06); 1015 sect->align = maxalign(s, SINITARR); 1016 datsize = rnd(datsize, sect->align); 1017 sect->vaddr = datsize; 1018 for(; s != nil && s->type == SINITARR; s = s->next) { 1019 datsize = aligndatsize(datsize, s); 1020 s->sect = sect; 1021 s->value = datsize - sect->vaddr; 1022 growdatsize(&datsize, s); 1023 } 1024 sect->len = datsize - sect->vaddr; 1025 } 1026 1027 /* data */ 1028 sect = addsection(&segdata, ".data", 06); 1029 sect->align = maxalign(s, SBSS-1); 1030 datsize = rnd(datsize, sect->align); 1031 sect->vaddr = datsize; 1032 linklookup(ctxt, "runtime.data", 0)->sect = sect; 1033 linklookup(ctxt, "runtime.edata", 0)->sect = sect; 1034 gcdata = linklookup(ctxt, "runtime.gcdata", 0); 1035 proggeninit(&gen, gcdata); 1036 for(; s != nil && s->type < SBSS; s = s->next) { 1037 if(s->type == SINITARR) { 1038 ctxt->cursym = s; 1039 diag("unexpected symbol type %d", s->type); 1040 } 1041 s->sect = sect; 1042 s->type = SDATA; 1043 datsize = aligndatsize(datsize, s); 1044 s->value = datsize - sect->vaddr; 1045 proggenaddsym(&gen, s); // gc 1046 growdatsize(&datsize, s); 1047 } 1048 sect->len = datsize - sect->vaddr; 1049 proggenfini(&gen, sect->len); // gc 1050 1051 /* bss */ 1052 sect = addsection(&segdata, ".bss", 06); 1053 sect->align = maxalign(s, SNOPTRBSS-1); 1054 datsize = rnd(datsize, sect->align); 1055 sect->vaddr = datsize; 1056 linklookup(ctxt, "runtime.bss", 0)->sect = sect; 1057 linklookup(ctxt, "runtime.ebss", 0)->sect = sect; 1058 gcbss = linklookup(ctxt, "runtime.gcbss", 0); 1059 proggeninit(&gen, gcbss); 1060 for(; s != nil && s->type < SNOPTRBSS; s = s->next) { 1061 s->sect = sect; 1062 datsize = aligndatsize(datsize, s); 1063 s->value = datsize - sect->vaddr; 1064 proggenaddsym(&gen, s); // gc 1065 growdatsize(&datsize, s); 1066 } 1067 sect->len = datsize - sect->vaddr; 1068 proggenfini(&gen, sect->len); // gc 1069 1070 /* pointer-free bss */ 1071 sect = addsection(&segdata, ".noptrbss", 06); 1072 sect->align = maxalign(s, SNOPTRBSS); 1073 datsize = rnd(datsize, sect->align); 1074 sect->vaddr = datsize; 1075 linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect; 1076 linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect; 1077 for(; s != nil && s->type == SNOPTRBSS; s = s->next) { 1078 datsize = aligndatsize(datsize, s); 1079 s->sect = sect; 1080 s->value = datsize - sect->vaddr; 1081 growdatsize(&datsize, s); 1082 } 1083 sect->len = datsize - sect->vaddr; 1084 linklookup(ctxt, "runtime.end", 0)->sect = sect; 1085 1086 // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. 1087 if(datsize != (uint32)datsize) { 1088 diag("data or bss segment too large"); 1089 } 1090 1091 if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) { 1092 sect = addsection(&segdata, ".tbss", 06); 1093 sect->align = PtrSize; 1094 sect->vaddr = 0; 1095 datsize = 0; 1096 for(; s != nil && s->type == STLSBSS; s = s->next) { 1097 datsize = aligndatsize(datsize, s); 1098 s->sect = sect; 1099 s->value = datsize - sect->vaddr; 1100 growdatsize(&datsize, s); 1101 } 1102 sect->len = datsize; 1103 } else { 1104 // Might be internal linking but still using cgo. 1105 // In that case, the only possible STLSBSS symbol is runtime.tlsg. 1106 // Give it offset 0, because it's the only thing here. 1107 if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsg") == 0) { 1108 s->value = 0; 1109 s = s->next; 1110 } 1111 } 1112 1113 if(s != nil) { 1114 ctxt->cursym = nil; 1115 diag("unexpected symbol type %d for %s", s->type, s->name); 1116 } 1117 1118 /* 1119 * We finished data, begin read-only data. 1120 * Not all systems support a separate read-only non-executable data section. 1121 * ELF systems do. 1122 * OS X and Plan 9 do not. 1123 * Windows PE may, but if so we have not implemented it. 1124 * And if we're using external linking mode, the point is moot, 1125 * since it's not our decision; that code expects the sections in 1126 * segtext. 1127 */ 1128 if(iself && linkmode == LinkInternal) 1129 segro = &segrodata; 1130 else 1131 segro = &segtext; 1132 1133 s = datap; 1134 1135 datsize = 0; 1136 1137 /* read-only executable ELF, Mach-O sections */ 1138 for(; s != nil && s->type < STYPE; s = s->next) { 1139 sect = addsection(&segtext, s->name, 04); 1140 sect->align = symalign(s); 1141 datsize = rnd(datsize, sect->align); 1142 sect->vaddr = datsize; 1143 s->sect = sect; 1144 s->type = SRODATA; 1145 s->value = datsize - sect->vaddr; 1146 growdatsize(&datsize, s); 1147 sect->len = datsize - sect->vaddr; 1148 } 1149 1150 /* read-only data */ 1151 sect = addsection(segro, ".rodata", 04); 1152 sect->align = maxalign(s, STYPELINK-1); 1153 datsize = rnd(datsize, sect->align); 1154 sect->vaddr = 0; 1155 linklookup(ctxt, "runtime.rodata", 0)->sect = sect; 1156 linklookup(ctxt, "runtime.erodata", 0)->sect = sect; 1157 for(; s != nil && s->type < STYPELINK; s = s->next) { 1158 datsize = aligndatsize(datsize, s); 1159 s->sect = sect; 1160 s->type = SRODATA; 1161 s->value = datsize - sect->vaddr; 1162 growdatsize(&datsize, s); 1163 } 1164 sect->len = datsize - sect->vaddr; 1165 1166 /* typelink */ 1167 sect = addsection(segro, ".typelink", 04); 1168 sect->align = maxalign(s, STYPELINK); 1169 datsize = rnd(datsize, sect->align); 1170 sect->vaddr = datsize; 1171 linklookup(ctxt, "runtime.typelink", 0)->sect = sect; 1172 linklookup(ctxt, "runtime.etypelink", 0)->sect = sect; 1173 for(; s != nil && s->type == STYPELINK; s = s->next) { 1174 datsize = aligndatsize(datsize, s); 1175 s->sect = sect; 1176 s->type = SRODATA; 1177 s->value = datsize - sect->vaddr; 1178 growdatsize(&datsize, s); 1179 } 1180 sect->len = datsize - sect->vaddr; 1181 1182 /* gosymtab */ 1183 sect = addsection(segro, ".gosymtab", 04); 1184 sect->align = maxalign(s, SPCLNTAB-1); 1185 datsize = rnd(datsize, sect->align); 1186 sect->vaddr = datsize; 1187 linklookup(ctxt, "runtime.symtab", 0)->sect = sect; 1188 linklookup(ctxt, "runtime.esymtab", 0)->sect = sect; 1189 for(; s != nil && s->type < SPCLNTAB; s = s->next) { 1190 datsize = aligndatsize(datsize, s); 1191 s->sect = sect; 1192 s->type = SRODATA; 1193 s->value = datsize - sect->vaddr; 1194 growdatsize(&datsize, s); 1195 } 1196 sect->len = datsize - sect->vaddr; 1197 1198 /* gopclntab */ 1199 sect = addsection(segro, ".gopclntab", 04); 1200 sect->align = maxalign(s, SELFROSECT-1); 1201 datsize = rnd(datsize, sect->align); 1202 sect->vaddr = datsize; 1203 linklookup(ctxt, "runtime.pclntab", 0)->sect = sect; 1204 linklookup(ctxt, "runtime.epclntab", 0)->sect = sect; 1205 for(; s != nil && s->type < SELFROSECT; s = s->next) { 1206 datsize = aligndatsize(datsize, s); 1207 s->sect = sect; 1208 s->type = SRODATA; 1209 s->value = datsize - sect->vaddr; 1210 growdatsize(&datsize, s); 1211 } 1212 sect->len = datsize - sect->vaddr; 1213 1214 /* read-only ELF, Mach-O sections */ 1215 for(; s != nil && s->type < SELFSECT; s = s->next) { 1216 sect = addsection(segro, s->name, 04); 1217 sect->align = symalign(s); 1218 datsize = rnd(datsize, sect->align); 1219 sect->vaddr = datsize; 1220 s->sect = sect; 1221 s->type = SRODATA; 1222 s->value = datsize - sect->vaddr; 1223 growdatsize(&datsize, s); 1224 sect->len = datsize - sect->vaddr; 1225 } 1226 1227 // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. 1228 if(datsize != (uint32)datsize) { 1229 diag("read-only data segment too large"); 1230 } 1231 1232 /* number the sections */ 1233 n = 1; 1234 for(sect = segtext.sect; sect != nil; sect = sect->next) 1235 sect->extnum = n++; 1236 for(sect = segrodata.sect; sect != nil; sect = sect->next) 1237 sect->extnum = n++; 1238 for(sect = segdata.sect; sect != nil; sect = sect->next) 1239 sect->extnum = n++; 1240 } 1241 1242 // assign addresses to text 1243 void 1244 textaddress(void) 1245 { 1246 uvlong va; 1247 Section *sect; 1248 LSym *sym, *sub; 1249 1250 addsection(&segtext, ".text", 05); 1251 1252 // Assign PCs in text segment. 1253 // Could parallelize, by assigning to text 1254 // and then letting threads copy down, but probably not worth it. 1255 sect = segtext.sect; 1256 sect->align = funcalign; 1257 linklookup(ctxt, "runtime.text", 0)->sect = sect; 1258 linklookup(ctxt, "runtime.etext", 0)->sect = sect; 1259 va = INITTEXT; 1260 sect->vaddr = va; 1261 for(sym = ctxt->textp; sym != nil; sym = sym->next) { 1262 sym->sect = sect; 1263 if(sym->type & SSUB) 1264 continue; 1265 if(sym->align != 0) 1266 va = rnd(va, sym->align); 1267 else 1268 va = rnd(va, funcalign); 1269 sym->value = 0; 1270 for(sub = sym; sub != S; sub = sub->sub) 1271 sub->value += va; 1272 if(sym->size == 0 && sym->sub != S) 1273 ctxt->cursym = sym; 1274 va += sym->size; 1275 } 1276 sect->len = va - sect->vaddr; 1277 } 1278 1279 // assign addresses 1280 void 1281 address(void) 1282 { 1283 Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; 1284 Section *typelink; 1285 LSym *sym, *sub; 1286 uvlong va; 1287 vlong vlen; 1288 1289 va = INITTEXT; 1290 segtext.rwx = 05; 1291 segtext.vaddr = va; 1292 segtext.fileoff = HEADR; 1293 for(s=segtext.sect; s != nil; s=s->next) { 1294 va = rnd(va, s->align); 1295 s->vaddr = va; 1296 va += s->len; 1297 } 1298 segtext.len = va - INITTEXT; 1299 segtext.filelen = segtext.len; 1300 if(HEADTYPE == Hnacl) 1301 va += 32; // room for the "halt sled" 1302 1303 if(segrodata.sect != nil) { 1304 // align to page boundary so as not to mix 1305 // rodata and executable text. 1306 va = rnd(va, INITRND); 1307 1308 segrodata.rwx = 04; 1309 segrodata.vaddr = va; 1310 segrodata.fileoff = va - segtext.vaddr + segtext.fileoff; 1311 segrodata.filelen = 0; 1312 for(s=segrodata.sect; s != nil; s=s->next) { 1313 va = rnd(va, s->align); 1314 s->vaddr = va; 1315 va += s->len; 1316 } 1317 segrodata.len = va - segrodata.vaddr; 1318 segrodata.filelen = segrodata.len; 1319 } 1320 1321 va = rnd(va, INITRND); 1322 segdata.rwx = 06; 1323 segdata.vaddr = va; 1324 segdata.fileoff = va - segtext.vaddr + segtext.fileoff; 1325 segdata.filelen = 0; 1326 if(HEADTYPE == Hwindows) 1327 segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); 1328 if(HEADTYPE == Hplan9) 1329 segdata.fileoff = segtext.fileoff + segtext.filelen; 1330 data = nil; 1331 noptr = nil; 1332 bss = nil; 1333 noptrbss = nil; 1334 for(s=segdata.sect; s != nil; s=s->next) { 1335 vlen = s->len; 1336 if(s->next) 1337 vlen = s->next->vaddr - s->vaddr; 1338 s->vaddr = va; 1339 va += vlen; 1340 segdata.len = va - segdata.vaddr; 1341 if(strcmp(s->name, ".data") == 0) 1342 data = s; 1343 if(strcmp(s->name, ".noptrdata") == 0) 1344 noptr = s; 1345 if(strcmp(s->name, ".bss") == 0) 1346 bss = s; 1347 if(strcmp(s->name, ".noptrbss") == 0) 1348 noptrbss = s; 1349 } 1350 segdata.filelen = bss->vaddr - segdata.vaddr; 1351 1352 text = segtext.sect; 1353 if(segrodata.sect) 1354 rodata = segrodata.sect; 1355 else 1356 rodata = text->next; 1357 typelink = rodata->next; 1358 symtab = typelink->next; 1359 pclntab = symtab->next; 1360 1361 for(sym = datap; sym != nil; sym = sym->next) { 1362 ctxt->cursym = sym; 1363 if(sym->sect != nil) 1364 sym->value += sym->sect->vaddr; 1365 for(sub = sym->sub; sub != nil; sub = sub->sub) 1366 sub->value += sym->value; 1367 } 1368 1369 xdefine("runtime.text", STEXT, text->vaddr); 1370 xdefine("runtime.etext", STEXT, text->vaddr + text->len); 1371 xdefine("runtime.rodata", SRODATA, rodata->vaddr); 1372 xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->len); 1373 xdefine("runtime.typelink", SRODATA, typelink->vaddr); 1374 xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->len); 1375 1376 sym = linklookup(ctxt, "runtime.gcdata", 0); 1377 xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size); 1378 linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect; 1379 1380 sym = linklookup(ctxt, "runtime.gcbss", 0); 1381 xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size); 1382 linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect; 1383 1384 xdefine("runtime.symtab", SRODATA, symtab->vaddr); 1385 xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->len); 1386 xdefine("runtime.pclntab", SRODATA, pclntab->vaddr); 1387 xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->len); 1388 xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr); 1389 xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); 1390 xdefine("runtime.bss", SBSS, bss->vaddr); 1391 xdefine("runtime.ebss", SBSS, bss->vaddr + bss->len); 1392 xdefine("runtime.data", SDATA, data->vaddr); 1393 xdefine("runtime.edata", SDATA, data->vaddr + data->len); 1394 xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr); 1395 xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); 1396 xdefine("runtime.end", SBSS, segdata.vaddr + segdata.len); 1397 }