github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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 "../../pkg/runtime/mgc0.h" 39 40 void dynreloc(void); 41 static vlong addaddrplus4(Sym *s, Sym *t, vlong add); 42 43 /* 44 * divide-and-conquer list-link 45 * sort of Sym* structures. 46 * Used for the data block. 47 */ 48 int 49 datcmp(Sym *s1, Sym *s2) 50 { 51 if(s1->type != s2->type) 52 return (int)s1->type - (int)s2->type; 53 if(s1->size != s2->size) { 54 if(s1->size < s2->size) 55 return -1; 56 return +1; 57 } 58 return strcmp(s1->name, s2->name); 59 } 60 61 Sym* 62 listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off) 63 { 64 Sym *l1, *l2, *le; 65 #define NEXT(l) (*(Sym**)((char*)(l)+off)) 66 67 if(l == 0 || NEXT(l) == 0) 68 return l; 69 70 l1 = l; 71 l2 = l; 72 for(;;) { 73 l2 = NEXT(l2); 74 if(l2 == 0) 75 break; 76 l2 = NEXT(l2); 77 if(l2 == 0) 78 break; 79 l1 = NEXT(l1); 80 } 81 82 l2 = NEXT(l1); 83 NEXT(l1) = 0; 84 l1 = listsort(l, cmp, off); 85 l2 = listsort(l2, cmp, off); 86 87 /* set up lead element */ 88 if(cmp(l1, l2) < 0) { 89 l = l1; 90 l1 = NEXT(l1); 91 } else { 92 l = l2; 93 l2 = NEXT(l2); 94 } 95 le = l; 96 97 for(;;) { 98 if(l1 == 0) { 99 while(l2) { 100 NEXT(le) = l2; 101 le = l2; 102 l2 = NEXT(l2); 103 } 104 NEXT(le) = 0; 105 break; 106 } 107 if(l2 == 0) { 108 while(l1) { 109 NEXT(le) = l1; 110 le = l1; 111 l1 = NEXT(l1); 112 } 113 break; 114 } 115 if(cmp(l1, l2) < 0) { 116 NEXT(le) = l1; 117 le = l1; 118 l1 = NEXT(l1); 119 } else { 120 NEXT(le) = l2; 121 le = l2; 122 l2 = NEXT(l2); 123 } 124 } 125 NEXT(le) = 0; 126 return l; 127 128 #undef NEXT 129 } 130 131 Reloc* 132 addrel(Sym *s) 133 { 134 if(s->nr >= s->maxr) { 135 if(s->maxr == 0) 136 s->maxr = 4; 137 else 138 s->maxr <<= 1; 139 s->r = erealloc(s->r, s->maxr*sizeof s->r[0]); 140 memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); 141 } 142 return &s->r[s->nr++]; 143 } 144 145 void 146 relocsym(Sym *s) 147 { 148 Reloc *r; 149 Sym *rs; 150 Prog p; 151 int32 i, off, siz, fl; 152 vlong o; 153 uchar *cast; 154 155 cursym = s; 156 memset(&p, 0, sizeof p); 157 for(r=s->r; r<s->r+s->nr; r++) { 158 r->done = 1; 159 off = r->off; 160 siz = r->siz; 161 if(off < 0 || off+siz > s->np) { 162 diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np); 163 continue; 164 } 165 if(r->sym != S && (r->sym->type & SMASK == 0 || r->sym->type & SMASK == SXREF)) { 166 diag("%s: not defined", r->sym->name); 167 continue; 168 } 169 if(r->type >= 256) 170 continue; 171 172 if(r->sym != S && r->sym->type == SDYNIMPORT) 173 diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type); 174 175 if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable) 176 diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); 177 178 switch(r->type) { 179 default: 180 o = 0; 181 if(linkmode == LinkExternal || archreloc(r, s, &o) < 0) 182 diag("unknown reloc %d", r->type); 183 break; 184 case D_TLS: 185 r->done = 0; 186 o = 0; 187 break; 188 case D_ADDR: 189 if(linkmode == LinkExternal && r->sym->type != SCONST) { 190 r->done = 0; 191 192 // set up addend for eventual relocation via outer symbol. 193 rs = r->sym; 194 r->xadd = r->add; 195 while(rs->outer != nil) { 196 r->xadd += symaddr(rs) - symaddr(rs->outer); 197 rs = rs->outer; 198 } 199 if(rs->type != SHOSTOBJ && rs->sect == nil) 200 diag("missing section for %s", rs->name); 201 r->xsym = rs; 202 203 o = r->xadd; 204 if(iself) { 205 if(thechar == '6') 206 o = 0; 207 } else if(HEADTYPE == Hdarwin) { 208 if(rs->type != SHOSTOBJ) 209 o += symaddr(rs); 210 } else { 211 diag("unhandled pcrel relocation for %s", headtype); 212 } 213 break; 214 } 215 o = symaddr(r->sym) + r->add; 216 break; 217 case D_PCREL: 218 // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. 219 if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) { 220 r->done = 0; 221 222 // set up addend for eventual relocation via outer symbol. 223 rs = r->sym; 224 r->xadd = r->add; 225 while(rs->outer != nil) { 226 r->xadd += symaddr(rs) - symaddr(rs->outer); 227 rs = rs->outer; 228 } 229 r->xadd -= r->siz; // relative to address after the relocated chunk 230 if(rs->type != SHOSTOBJ && rs->sect == nil) 231 diag("missing section for %s", rs->name); 232 r->xsym = rs; 233 234 o = r->xadd; 235 if(iself) { 236 if(thechar == '6') 237 o = 0; 238 } else if(HEADTYPE == Hdarwin) { 239 if(rs->type != SHOSTOBJ) 240 o += symaddr(rs) - rs->sect->vaddr; 241 o -= r->off; // WTF? 242 } else { 243 diag("unhandled pcrel relocation for %s", headtype); 244 } 245 break; 246 } 247 o = 0; 248 if(r->sym) 249 o += symaddr(r->sym); 250 // NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c 251 // compiler. The expression s->value + r->off + r->siz is int32 + int32 + 252 // uchar, and Plan 9 8c incorrectly treats the expression as type uint32 253 // instead of int32, causing incorrect values when sign extended for adding 254 // to o. The bug only occurs on Plan 9, because this C program is compiled by 255 // the standard host compiler (gcc on most other systems). 256 o += r->add - (s->value + r->off + (int32)r->siz); 257 break; 258 case D_SIZE: 259 o = r->sym->size + r->add; 260 break; 261 } 262 //print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o); 263 switch(siz) { 264 default: 265 cursym = s; 266 diag("bad reloc size %#ux for %s", siz, r->sym->name); 267 case 4: 268 if(r->type == D_PCREL) { 269 if(o != (int32)o) 270 diag("pc-relative relocation address is too big: %#llx", o); 271 } else { 272 if(o != (int32)o && o != (uint32)o) 273 diag("non-pc-relative relocation address is too big: %#llux", o); 274 } 275 fl = o; 276 cast = (uchar*)&fl; 277 for(i=0; i<4; i++) 278 s->p[off+i] = cast[inuxi4[i]]; 279 break; 280 case 8: 281 cast = (uchar*)&o; 282 for(i=0; i<8; i++) 283 s->p[off+i] = cast[inuxi8[i]]; 284 break; 285 } 286 } 287 } 288 289 void 290 reloc(void) 291 { 292 Sym *s; 293 294 if(debug['v']) 295 Bprint(&bso, "%5.2f reloc\n", cputime()); 296 Bflush(&bso); 297 298 for(s=textp; s!=S; s=s->next) 299 relocsym(s); 300 for(s=datap; s!=S; s=s->next) 301 relocsym(s); 302 } 303 304 void 305 dynrelocsym(Sym *s) 306 { 307 Reloc *r; 308 Sym *rel; 309 Sym *got; 310 311 if(HEADTYPE == Hwindows) { 312 Sym *rel, *targ; 313 314 rel = lookup(".rel", 0); 315 if(s == rel) 316 return; 317 for(r=s->r; r<s->r+s->nr; r++) { 318 targ = r->sym; 319 if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files. 320 targ->plt = rel->size; 321 r->sym = rel; 322 r->add = targ->plt; 323 324 // jmp *addr 325 if(thechar == '8') { 326 adduint8(rel, 0xff); 327 adduint8(rel, 0x25); 328 addaddr(rel, targ); 329 adduint8(rel, 0x90); 330 adduint8(rel, 0x90); 331 } else { 332 adduint8(rel, 0xff); 333 adduint8(rel, 0x24); 334 adduint8(rel, 0x25); 335 addaddrplus4(rel, targ, 0); 336 adduint8(rel, 0x90); 337 } 338 } else if(r->sym->plt >= 0) { 339 r->sym = rel; 340 r->add = targ->plt; 341 } 342 } 343 return; 344 } 345 346 got = rel = nil; 347 if(flag_shared) { 348 rel = lookuprel(); 349 got = lookup(".got", 0); 350 } 351 s->rel_ro = 0; 352 for(r=s->r; r<s->r+s->nr; r++) { 353 if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) 354 adddynrel(s, r); 355 if(flag_shared && r->sym != S && s->type != SDYNIMPORT && r->type == D_ADDR 356 && (s == got || s->type == SDATA || s->type == SGOSTRING || s->type == STYPE || s->type == SRODATA)) { 357 // Create address based RELATIVE relocation 358 adddynrela(rel, s, r); 359 if(s->type < SNOPTRDATA) 360 s->rel_ro = 1; 361 } 362 } 363 } 364 365 void 366 dynreloc(void) 367 { 368 Sym *s; 369 370 // -d supresses dynamic loader format, so we may as well not 371 // compute these sections or mark their symbols as reachable. 372 if(debug['d'] && HEADTYPE != Hwindows) 373 return; 374 if(debug['v']) 375 Bprint(&bso, "%5.2f reloc\n", cputime()); 376 Bflush(&bso); 377 378 for(s=textp; s!=S; s=s->next) 379 dynrelocsym(s); 380 for(s=datap; s!=S; s=s->next) 381 dynrelocsym(s); 382 if(iself) 383 elfdynhash(); 384 } 385 386 void 387 symgrow(Sym *s, int32 siz) 388 { 389 if(s->np >= siz) 390 return; 391 392 if(s->maxp < siz) { 393 if(s->maxp == 0) 394 s->maxp = 8; 395 while(s->maxp < siz) 396 s->maxp <<= 1; 397 s->p = erealloc(s->p, s->maxp); 398 memset(s->p+s->np, 0, s->maxp-s->np); 399 } 400 s->np = siz; 401 } 402 403 void 404 savedata(Sym *s, Prog *p, char *pn) 405 { 406 int32 off, siz, i, fl; 407 uchar *cast; 408 vlong o; 409 Reloc *r; 410 411 off = p->from.offset; 412 siz = p->datasize; 413 if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) 414 mangle(pn); 415 symgrow(s, off+siz); 416 417 switch(p->to.type) { 418 default: 419 diag("bad data: %P", p); 420 break; 421 422 case D_FCONST: 423 switch(siz) { 424 default: 425 case 4: 426 fl = ieeedtof(&p->to.ieee); 427 cast = (uchar*)&fl; 428 for(i=0; i<4; i++) 429 s->p[off+i] = cast[fnuxi4[i]]; 430 break; 431 case 8: 432 cast = (uchar*)&p->to.ieee; 433 for(i=0; i<8; i++) 434 s->p[off+i] = cast[fnuxi8[i]]; 435 break; 436 } 437 break; 438 439 case D_SCONST: 440 for(i=0; i<siz; i++) 441 s->p[off+i] = p->to.scon[i]; 442 break; 443 444 case D_CONST: 445 if(p->to.sym) 446 goto Addr; 447 o = p->to.offset; 448 fl = o; 449 cast = (uchar*)&fl; 450 switch(siz) { 451 default: 452 diag("bad nuxi %d\n%P", siz, p); 453 break; 454 case 1: 455 s->p[off] = cast[inuxi1[0]]; 456 break; 457 case 2: 458 for(i=0; i<2; i++) 459 s->p[off+i] = cast[inuxi2[i]]; 460 break; 461 case 4: 462 for(i=0; i<4; i++) 463 s->p[off+i] = cast[inuxi4[i]]; 464 break; 465 case 8: 466 cast = (uchar*)&o; 467 for(i=0; i<8; i++) 468 s->p[off+i] = cast[inuxi8[i]]; 469 break; 470 } 471 break; 472 473 case D_ADDR: 474 case D_SIZE: 475 Addr: 476 r = addrel(s); 477 r->off = off; 478 r->siz = siz; 479 r->sym = p->to.sym; 480 r->type = p->to.type; 481 if(r->type != D_SIZE) 482 r->type = D_ADDR; 483 r->add = p->to.offset; 484 break; 485 } 486 } 487 488 static void 489 blk(Sym *start, int32 addr, int32 size) 490 { 491 Sym *sym; 492 int32 eaddr; 493 uchar *p, *ep; 494 495 for(sym = start; sym != nil; sym = sym->next) 496 if(!(sym->type&SSUB) && sym->value >= addr) 497 break; 498 499 eaddr = addr+size; 500 for(; sym != nil; sym = sym->next) { 501 if(sym->type&SSUB) 502 continue; 503 if(sym->value >= eaddr) 504 break; 505 if(sym->value < addr) { 506 diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); 507 errorexit(); 508 } 509 cursym = sym; 510 for(; addr < sym->value; addr++) 511 cput(0); 512 p = sym->p; 513 ep = p + sym->np; 514 while(p < ep) 515 cput(*p++); 516 addr += sym->np; 517 for(; addr < sym->value+sym->size; addr++) 518 cput(0); 519 if(addr != sym->value+sym->size) { 520 diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size); 521 errorexit(); 522 } 523 } 524 525 for(; addr < eaddr; addr++) 526 cput(0); 527 cflush(); 528 } 529 530 void 531 codeblk(int32 addr, int32 size) 532 { 533 Sym *sym; 534 int32 eaddr, n, epc; 535 Prog *p; 536 uchar *q; 537 538 if(debug['a']) 539 Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); 540 541 blk(textp, addr, size); 542 543 /* again for printing */ 544 if(!debug['a']) 545 return; 546 547 for(sym = textp; sym != nil; sym = sym->next) { 548 if(!sym->reachable) 549 continue; 550 if(sym->value >= addr) 551 break; 552 } 553 554 eaddr = addr + size; 555 for(; sym != nil; sym = sym->next) { 556 if(!sym->reachable) 557 continue; 558 if(sym->value >= eaddr) 559 break; 560 561 if(addr < sym->value) { 562 Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); 563 for(; addr < sym->value; addr++) 564 Bprint(&bso, " %.2ux", 0); 565 Bprint(&bso, "\n"); 566 } 567 p = sym->text; 568 if(p == nil) { 569 Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name); 570 n = sym->size; 571 q = sym->p; 572 573 while(n >= 16) { 574 Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q); 575 addr += 16; 576 q += 16; 577 n -= 16; 578 } 579 if(n > 0) 580 Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q); 581 addr += n; 582 continue; 583 } 584 585 Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p); 586 for(p = p->link; p != P; p = p->link) { 587 if(p->link != P) 588 epc = p->link->pc; 589 else 590 epc = sym->value + sym->size; 591 Bprint(&bso, "%.6llux\t", (uvlong)p->pc); 592 q = sym->p + p->pc - sym->value; 593 n = epc - p->pc; 594 Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p); 595 addr += n; 596 } 597 } 598 599 if(addr < eaddr) { 600 Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); 601 for(; addr < eaddr; addr++) 602 Bprint(&bso, " %.2ux", 0); 603 } 604 Bflush(&bso); 605 } 606 607 void 608 datblk(int32 addr, int32 size) 609 { 610 Sym *sym; 611 int32 i, eaddr; 612 uchar *p, *ep; 613 char *typ, *rsname; 614 Reloc *r; 615 616 if(debug['a']) 617 Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); 618 619 blk(datap, addr, size); 620 621 /* again for printing */ 622 if(!debug['a']) 623 return; 624 625 for(sym = datap; sym != nil; sym = sym->next) 626 if(sym->value >= addr) 627 break; 628 629 eaddr = addr + size; 630 for(; sym != nil; sym = sym->next) { 631 if(sym->value >= eaddr) 632 break; 633 if(addr < sym->value) { 634 Bprint(&bso, "\t%.8ux| 00 ...\n", addr); 635 addr = sym->value; 636 } 637 Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr); 638 p = sym->p; 639 ep = p + sym->np; 640 while(p < ep) { 641 if(p > sym->p && (int)(p-sym->p)%16 == 0) 642 Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p))); 643 Bprint(&bso, " %.2ux", *p++); 644 } 645 addr += sym->np; 646 for(; addr < sym->value+sym->size; addr++) 647 Bprint(&bso, " %.2ux", 0); 648 Bprint(&bso, "\n"); 649 650 if(linkmode == LinkExternal) { 651 for(i=0; i<sym->nr; i++) { 652 r = &sym->r[i]; 653 rsname = ""; 654 if(r->sym) 655 rsname = r->sym->name; 656 typ = "?"; 657 switch(r->type) { 658 case D_ADDR: 659 typ = "addr"; 660 break; 661 case D_PCREL: 662 typ = "pcrel"; 663 break; 664 } 665 Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n", 666 (uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add)); 667 } 668 } 669 } 670 671 if(addr < eaddr) 672 Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr); 673 Bprint(&bso, "\t%.8ux|\n", (uint)eaddr); 674 } 675 676 void 677 strnput(char *s, int n) 678 { 679 for(; n > 0 && *s; s++) { 680 cput(*s); 681 n--; 682 } 683 while(n > 0) { 684 cput(0); 685 n--; 686 } 687 } 688 689 void 690 addstrdata(char *name, char *value) 691 { 692 Sym *s, *sp; 693 char *p; 694 695 p = smprint("%s.str", name); 696 sp = lookup(p, 0); 697 free(p); 698 addstring(sp, value); 699 700 s = lookup(name, 0); 701 s->size = 0; 702 s->dupok = 1; 703 addaddr(s, sp); 704 adduint32(s, strlen(value)); 705 if(PtrSize == 8) 706 adduint32(s, 0); // round struct to pointer width 707 708 // in case reachability has already been computed 709 sp->reachable = s->reachable; 710 } 711 712 vlong 713 addstring(Sym *s, char *str) 714 { 715 int n; 716 int32 r; 717 718 if(s->type == 0) 719 s->type = SNOPTRDATA; 720 s->reachable = 1; 721 r = s->size; 722 n = strlen(str)+1; 723 if(strcmp(s->name, ".shstrtab") == 0) 724 elfsetstring(str, r); 725 symgrow(s, r+n); 726 memmove(s->p+r, str, n); 727 s->size += n; 728 return r; 729 } 730 731 vlong 732 setuintxx(Sym *s, vlong off, uint64 v, vlong wid) 733 { 734 int32 i, fl; 735 vlong o; 736 uchar *cast; 737 738 if(s->type == 0) 739 s->type = SDATA; 740 s->reachable = 1; 741 if(s->size < off+wid) { 742 s->size = off+wid; 743 symgrow(s, s->size); 744 } 745 fl = v; 746 cast = (uchar*)&fl; 747 switch(wid) { 748 case 1: 749 s->p[off] = cast[inuxi1[0]]; 750 break; 751 case 2: 752 for(i=0; i<2; i++) 753 s->p[off+i] = cast[inuxi2[i]]; 754 break; 755 case 4: 756 for(i=0; i<4; i++) 757 s->p[off+i] = cast[inuxi4[i]]; 758 break; 759 case 8: 760 o = v; 761 cast = (uchar*)&o; 762 for(i=0; i<8; i++) 763 s->p[off+i] = cast[inuxi8[i]]; 764 break; 765 } 766 return off; 767 } 768 769 vlong 770 adduintxx(Sym *s, uint64 v, int wid) 771 { 772 vlong off; 773 774 off = s->size; 775 setuintxx(s, off, v, wid); 776 return off; 777 } 778 779 vlong 780 adduint8(Sym *s, uint8 v) 781 { 782 return adduintxx(s, v, 1); 783 } 784 785 vlong 786 adduint16(Sym *s, uint16 v) 787 { 788 return adduintxx(s, v, 2); 789 } 790 791 vlong 792 adduint32(Sym *s, uint32 v) 793 { 794 return adduintxx(s, v, 4); 795 } 796 797 vlong 798 adduint64(Sym *s, uint64 v) 799 { 800 return adduintxx(s, v, 8); 801 } 802 803 void 804 setuint8(Sym *s, vlong r, uint8 v) 805 { 806 setuintxx(s, r, v, 1); 807 } 808 809 void 810 setuint16(Sym *s, vlong r, uint16 v) 811 { 812 setuintxx(s, r, v, 2); 813 } 814 815 void 816 setuint32(Sym *s, vlong r, uint32 v) 817 { 818 setuintxx(s, r, v, 4); 819 } 820 821 void 822 setuint64(Sym *s, vlong r, uint64 v) 823 { 824 setuintxx(s, r, v, 8); 825 } 826 827 vlong 828 addaddrplus(Sym *s, Sym *t, vlong add) 829 { 830 vlong i; 831 Reloc *r; 832 833 if(s->type == 0) 834 s->type = SDATA; 835 s->reachable = 1; 836 i = s->size; 837 s->size += PtrSize; 838 symgrow(s, s->size); 839 r = addrel(s); 840 r->sym = t; 841 r->off = i; 842 r->siz = PtrSize; 843 r->type = D_ADDR; 844 r->add = add; 845 return i; 846 } 847 848 static vlong 849 addaddrplus4(Sym *s, Sym *t, vlong add) 850 { 851 vlong i; 852 Reloc *r; 853 854 if(s->type == 0) 855 s->type = SDATA; 856 s->reachable = 1; 857 i = s->size; 858 s->size += 4; 859 symgrow(s, s->size); 860 r = addrel(s); 861 r->sym = t; 862 r->off = i; 863 r->siz = 4; 864 r->type = D_ADDR; 865 r->add = add; 866 return i; 867 } 868 869 vlong 870 addpcrelplus(Sym *s, Sym *t, vlong add) 871 { 872 vlong i; 873 Reloc *r; 874 875 if(s->type == 0) 876 s->type = SDATA; 877 s->reachable = 1; 878 i = s->size; 879 s->size += 4; 880 symgrow(s, s->size); 881 r = addrel(s); 882 r->sym = t; 883 r->off = i; 884 r->add = add; 885 r->type = D_PCREL; 886 r->siz = 4; 887 return i; 888 } 889 890 vlong 891 addaddr(Sym *s, Sym *t) 892 { 893 return addaddrplus(s, t, 0); 894 } 895 896 vlong 897 setaddrplus(Sym *s, vlong off, Sym *t, vlong add) 898 { 899 Reloc *r; 900 901 if(s->type == 0) 902 s->type = SDATA; 903 s->reachable = 1; 904 if(off+PtrSize > s->size) { 905 s->size = off + PtrSize; 906 symgrow(s, s->size); 907 } 908 r = addrel(s); 909 r->sym = t; 910 r->off = off; 911 r->siz = PtrSize; 912 r->type = D_ADDR; 913 r->add = add; 914 return off; 915 } 916 917 vlong 918 setaddr(Sym *s, vlong off, Sym *t) 919 { 920 return setaddrplus(s, off, t, 0); 921 } 922 923 vlong 924 addsize(Sym *s, Sym *t) 925 { 926 vlong i; 927 Reloc *r; 928 929 if(s->type == 0) 930 s->type = SDATA; 931 s->reachable = 1; 932 i = s->size; 933 s->size += PtrSize; 934 symgrow(s, s->size); 935 r = addrel(s); 936 r->sym = t; 937 r->off = i; 938 r->siz = PtrSize; 939 r->type = D_SIZE; 940 return i; 941 } 942 943 void 944 dosymtype(void) 945 { 946 Sym *s; 947 948 for(s = allsym; s != nil; s = s->allsym) { 949 if(s->np > 0) { 950 if(s->type == SBSS) 951 s->type = SDATA; 952 if(s->type == SNOPTRBSS) 953 s->type = SNOPTRDATA; 954 } 955 } 956 } 957 958 static int32 959 symalign(Sym *s) 960 { 961 int32 align; 962 963 if(s->align != 0) 964 return s->align; 965 966 align = MaxAlign; 967 while(align > s->size && align > 1) 968 align >>= 1; 969 if(align < s->align) 970 align = s->align; 971 return align; 972 } 973 974 static vlong 975 aligndatsize(vlong datsize, Sym *s) 976 { 977 return rnd(datsize, symalign(s)); 978 } 979 980 // maxalign returns the maximum required alignment for 981 // the list of symbols s; the list stops when s->type exceeds type. 982 static int32 983 maxalign(Sym *s, int type) 984 { 985 int32 align, max; 986 987 max = 0; 988 for(; s != S && s->type <= type; s = s->next) { 989 align = symalign(s); 990 if(max < align) 991 max = align; 992 } 993 return max; 994 } 995 996 static void 997 gcaddsym(Sym *gc, Sym *s, vlong off) 998 { 999 vlong a; 1000 Sym *gotype; 1001 1002 if(s->size < PtrSize) 1003 return; 1004 if(strcmp(s->name, ".string") == 0) 1005 return; 1006 1007 gotype = s->gotype; 1008 if(gotype != nil) { 1009 //print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name); 1010 adduintxx(gc, GC_CALL, PtrSize); 1011 adduintxx(gc, off, PtrSize); 1012 addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4); 1013 if(PtrSize == 8) 1014 adduintxx(gc, 0, 4); 1015 } else { 1016 //print("gcaddsym: %s %d <unknown type>\n", s->name, s->size); 1017 for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) { 1018 adduintxx(gc, GC_APTR, PtrSize); 1019 adduintxx(gc, off+a, PtrSize); 1020 } 1021 } 1022 } 1023 1024 void 1025 growdatsize(vlong *datsizep, Sym *s) 1026 { 1027 vlong datsize; 1028 1029 datsize = *datsizep; 1030 if(s->size < 0) 1031 diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size); 1032 if(datsize + s->size < datsize) 1033 diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size); 1034 *datsizep = datsize + s->size; 1035 } 1036 1037 void 1038 dodata(void) 1039 { 1040 int32 n; 1041 vlong datsize; 1042 Section *sect; 1043 Sym *s, *last, **l; 1044 Sym *gcdata1, *gcbss1; 1045 1046 if(debug['v']) 1047 Bprint(&bso, "%5.2f dodata\n", cputime()); 1048 Bflush(&bso); 1049 1050 // define garbage collection symbols 1051 gcdata1 = lookup("gcdata", 0); 1052 gcdata1->type = STYPE; 1053 gcdata1->reachable = 1; 1054 gcbss1 = lookup("gcbss", 0); 1055 gcbss1->type = STYPE; 1056 gcbss1->reachable = 1; 1057 1058 // size of .data and .bss section. the zero value is later replaced by the actual size of the section. 1059 adduintxx(gcdata1, 0, PtrSize); 1060 adduintxx(gcbss1, 0, PtrSize); 1061 1062 last = nil; 1063 datap = nil; 1064 1065 for(s=allsym; s!=S; s=s->allsym) { 1066 if(!s->reachable || s->special) 1067 continue; 1068 if(STEXT < s->type && s->type < SXREF) { 1069 if(last == nil) 1070 datap = s; 1071 else 1072 last->next = s; 1073 s->next = nil; 1074 last = s; 1075 } 1076 } 1077 1078 for(s = datap; s != nil; s = s->next) { 1079 if(s->np > s->size) 1080 diag("%s: initialize bounds (%lld < %d)", 1081 s->name, (vlong)s->size, s->np); 1082 } 1083 1084 1085 /* 1086 * now that we have the datap list, but before we start 1087 * to assign addresses, record all the necessary 1088 * dynamic relocations. these will grow the relocation 1089 * symbol, which is itself data. 1090 * 1091 * on darwin, we need the symbol table numbers for dynreloc. 1092 */ 1093 if(HEADTYPE == Hdarwin) 1094 machosymorder(); 1095 dynreloc(); 1096 1097 /* some symbols may no longer belong in datap (Mach-O) */ 1098 for(l=&datap; (s=*l) != nil; ) { 1099 if(s->type <= STEXT || SXREF <= s->type) 1100 *l = s->next; 1101 else 1102 l = &s->next; 1103 } 1104 *l = nil; 1105 1106 if(flag_shared) { 1107 for(s=datap; s != nil; s = s->next) { 1108 if(s->rel_ro) 1109 s->type = SDATARELRO; 1110 } 1111 } 1112 datap = listsort(datap, datcmp, offsetof(Sym, next)); 1113 1114 /* 1115 * allocate sections. list is sorted by type, 1116 * so we can just walk it for each piece we want to emit. 1117 * segdata is processed before segtext, because we need 1118 * to see all symbols in the .data and .bss sections in order 1119 * to generate garbage collection information. 1120 */ 1121 1122 /* begin segdata */ 1123 1124 /* skip symbols belonging to segtext */ 1125 s = datap; 1126 for(; s != nil && s->type < SELFSECT; s = s->next) 1127 ; 1128 1129 /* writable ELF sections */ 1130 datsize = 0; 1131 for(; s != nil && s->type < SNOPTRDATA; s = s->next) { 1132 sect = addsection(&segdata, s->name, 06); 1133 sect->align = symalign(s); 1134 datsize = rnd(datsize, sect->align); 1135 sect->vaddr = datsize; 1136 s->sect = sect; 1137 s->type = SDATA; 1138 s->value = datsize; 1139 growdatsize(&datsize, s); 1140 sect->len = datsize - sect->vaddr; 1141 } 1142 1143 /* pointer-free data */ 1144 sect = addsection(&segdata, ".noptrdata", 06); 1145 sect->align = maxalign(s, SDATARELRO-1); 1146 datsize = rnd(datsize, sect->align); 1147 sect->vaddr = datsize; 1148 lookup("noptrdata", 0)->sect = sect; 1149 lookup("enoptrdata", 0)->sect = sect; 1150 for(; s != nil && s->type < SDATARELRO; s = s->next) { 1151 datsize = aligndatsize(datsize, s); 1152 s->sect = sect; 1153 s->type = SDATA; 1154 s->value = datsize; 1155 growdatsize(&datsize, s); 1156 } 1157 sect->len = datsize - sect->vaddr; 1158 1159 /* dynamic relocated rodata */ 1160 if(flag_shared) { 1161 sect = addsection(&segdata, ".data.rel.ro", 06); 1162 sect->align = maxalign(s, SDATARELRO); 1163 datsize = rnd(datsize, sect->align); 1164 sect->vaddr = datsize; 1165 lookup("datarelro", 0)->sect = sect; 1166 lookup("edatarelro", 0)->sect = sect; 1167 for(; s != nil && s->type == SDATARELRO; s = s->next) { 1168 datsize = aligndatsize(datsize, s); 1169 s->sect = sect; 1170 s->type = SDATA; 1171 s->value = datsize; 1172 growdatsize(&datsize, s); 1173 } 1174 sect->len = datsize - sect->vaddr; 1175 } 1176 1177 /* data */ 1178 sect = addsection(&segdata, ".data", 06); 1179 sect->align = maxalign(s, SBSS-1); 1180 datsize = rnd(datsize, sect->align); 1181 sect->vaddr = datsize; 1182 lookup("data", 0)->sect = sect; 1183 lookup("edata", 0)->sect = sect; 1184 for(; s != nil && s->type < SBSS; s = s->next) { 1185 if(s->type == SDATARELRO) { 1186 cursym = s; 1187 diag("unexpected symbol type %d", s->type); 1188 } 1189 s->sect = sect; 1190 s->type = SDATA; 1191 datsize = aligndatsize(datsize, s); 1192 s->value = datsize; 1193 gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc 1194 growdatsize(&datsize, s); 1195 } 1196 sect->len = datsize - sect->vaddr; 1197 1198 adduintxx(gcdata1, GC_END, PtrSize); 1199 setuintxx(gcdata1, 0, sect->len, PtrSize); 1200 1201 /* bss */ 1202 sect = addsection(&segdata, ".bss", 06); 1203 sect->align = maxalign(s, SNOPTRBSS-1); 1204 datsize = rnd(datsize, sect->align); 1205 sect->vaddr = datsize; 1206 lookup("bss", 0)->sect = sect; 1207 lookup("ebss", 0)->sect = sect; 1208 for(; s != nil && s->type < SNOPTRBSS; s = s->next) { 1209 s->sect = sect; 1210 datsize = aligndatsize(datsize, s); 1211 s->value = datsize; 1212 gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc 1213 growdatsize(&datsize, s); 1214 } 1215 sect->len = datsize - sect->vaddr; 1216 1217 adduintxx(gcbss1, GC_END, PtrSize); 1218 setuintxx(gcbss1, 0, sect->len, PtrSize); 1219 1220 /* pointer-free bss */ 1221 sect = addsection(&segdata, ".noptrbss", 06); 1222 sect->align = maxalign(s, SNOPTRBSS); 1223 datsize = rnd(datsize, sect->align); 1224 sect->vaddr = datsize; 1225 lookup("noptrbss", 0)->sect = sect; 1226 lookup("enoptrbss", 0)->sect = sect; 1227 for(; s != nil && s->type == SNOPTRBSS; s = s->next) { 1228 datsize = aligndatsize(datsize, s); 1229 s->sect = sect; 1230 s->value = datsize; 1231 growdatsize(&datsize, s); 1232 } 1233 sect->len = datsize - sect->vaddr; 1234 lookup("end", 0)->sect = sect; 1235 1236 // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. 1237 if(datsize != (uint32)datsize) { 1238 diag("data or bss segment too large"); 1239 } 1240 1241 if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) { 1242 sect = addsection(&segdata, ".tbss", 06); 1243 sect->align = PtrSize; 1244 sect->vaddr = 0; 1245 datsize = 0; 1246 for(; s != nil && s->type == STLSBSS; s = s->next) { 1247 datsize = aligndatsize(datsize, s); 1248 s->sect = sect; 1249 s->value = datsize; 1250 growdatsize(&datsize, s); 1251 } 1252 sect->len = datsize; 1253 } 1254 1255 if(s != nil) { 1256 cursym = nil; 1257 diag("unexpected symbol type %d for %s", s->type, s->name); 1258 } 1259 1260 /* we finished segdata, begin segtext */ 1261 s = datap; 1262 1263 /* read-only data */ 1264 sect = addsection(&segtext, ".rodata", 04); 1265 sect->align = maxalign(s, STYPELINK-1); 1266 sect->vaddr = 0; 1267 lookup("rodata", 0)->sect = sect; 1268 lookup("erodata", 0)->sect = sect; 1269 datsize = 0; 1270 for(; s != nil && s->type < STYPELINK; s = s->next) { 1271 datsize = aligndatsize(datsize, s); 1272 s->sect = sect; 1273 s->type = SRODATA; 1274 s->value = datsize; 1275 growdatsize(&datsize, s); 1276 } 1277 sect->len = datsize - sect->vaddr; 1278 1279 /* typelink */ 1280 sect = addsection(&segtext, ".typelink", 04); 1281 sect->align = maxalign(s, STYPELINK); 1282 datsize = rnd(datsize, sect->align); 1283 sect->vaddr = datsize; 1284 lookup("typelink", 0)->sect = sect; 1285 lookup("etypelink", 0)->sect = sect; 1286 for(; s != nil && s->type == STYPELINK; s = s->next) { 1287 datsize = aligndatsize(datsize, s); 1288 s->sect = sect; 1289 s->type = SRODATA; 1290 s->value = datsize; 1291 growdatsize(&datsize, s); 1292 } 1293 sect->len = datsize - sect->vaddr; 1294 1295 /* gosymtab */ 1296 sect = addsection(&segtext, ".gosymtab", 04); 1297 sect->align = maxalign(s, SPCLNTAB-1); 1298 datsize = rnd(datsize, sect->align); 1299 sect->vaddr = datsize; 1300 lookup("symtab", 0)->sect = sect; 1301 lookup("esymtab", 0)->sect = sect; 1302 for(; s != nil && s->type < SPCLNTAB; s = s->next) { 1303 datsize = aligndatsize(datsize, s); 1304 s->sect = sect; 1305 s->type = SRODATA; 1306 s->value = datsize; 1307 growdatsize(&datsize, s); 1308 } 1309 sect->len = datsize - sect->vaddr; 1310 1311 /* gopclntab */ 1312 sect = addsection(&segtext, ".gopclntab", 04); 1313 sect->align = maxalign(s, SELFROSECT-1); 1314 datsize = rnd(datsize, sect->align); 1315 sect->vaddr = datsize; 1316 lookup("pclntab", 0)->sect = sect; 1317 lookup("epclntab", 0)->sect = sect; 1318 for(; s != nil && s->type < SELFROSECT; s = s->next) { 1319 datsize = aligndatsize(datsize, s); 1320 s->sect = sect; 1321 s->type = SRODATA; 1322 s->value = datsize; 1323 growdatsize(&datsize, s); 1324 } 1325 sect->len = datsize - sect->vaddr; 1326 1327 /* read-only ELF, Mach-O sections */ 1328 for(; s != nil && s->type < SELFSECT; s = s->next) { 1329 sect = addsection(&segtext, s->name, 04); 1330 sect->align = symalign(s); 1331 datsize = rnd(datsize, sect->align); 1332 sect->vaddr = datsize; 1333 s->sect = sect; 1334 s->type = SRODATA; 1335 s->value = datsize; 1336 growdatsize(&datsize, s); 1337 sect->len = datsize - sect->vaddr; 1338 } 1339 1340 // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. 1341 if(datsize != (uint32)datsize) { 1342 diag("text segment too large"); 1343 } 1344 1345 /* number the sections */ 1346 n = 1; 1347 for(sect = segtext.sect; sect != nil; sect = sect->next) 1348 sect->extnum = n++; 1349 for(sect = segdata.sect; sect != nil; sect = sect->next) 1350 sect->extnum = n++; 1351 } 1352 1353 // assign addresses to text 1354 void 1355 textaddress(void) 1356 { 1357 uvlong va; 1358 Prog *p; 1359 Section *sect; 1360 Sym *sym, *sub; 1361 1362 addsection(&segtext, ".text", 05); 1363 1364 // Assign PCs in text segment. 1365 // Could parallelize, by assigning to text 1366 // and then letting threads copy down, but probably not worth it. 1367 sect = segtext.sect; 1368 sect->align = FuncAlign; 1369 lookup("text", 0)->sect = sect; 1370 lookup("etext", 0)->sect = sect; 1371 va = INITTEXT; 1372 sect->vaddr = va; 1373 for(sym = textp; sym != nil; sym = sym->next) { 1374 sym->sect = sect; 1375 if(sym->type & SSUB) 1376 continue; 1377 if(sym->align != 0) 1378 va = rnd(va, sym->align); 1379 else if(sym->text != P) 1380 va = rnd(va, FuncAlign); 1381 sym->value = 0; 1382 for(sub = sym; sub != S; sub = sub->sub) { 1383 sub->value += va; 1384 for(p = sub->text; p != P; p = p->link) 1385 p->pc += sub->value; 1386 } 1387 if(sym->size == 0 && sym->sub != S) { 1388 cursym = sym; 1389 } 1390 va += sym->size; 1391 } 1392 sect->len = va - sect->vaddr; 1393 } 1394 1395 // assign addresses 1396 void 1397 address(void) 1398 { 1399 Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss, *datarelro; 1400 Section *typelink; 1401 Sym *sym, *sub; 1402 uvlong va; 1403 vlong vlen; 1404 1405 va = INITTEXT; 1406 segtext.rwx = 05; 1407 segtext.vaddr = va; 1408 segtext.fileoff = HEADR; 1409 for(s=segtext.sect; s != nil; s=s->next) { 1410 va = rnd(va, s->align); 1411 s->vaddr = va; 1412 va += s->len; 1413 } 1414 segtext.len = va - INITTEXT; 1415 segtext.filelen = segtext.len; 1416 1417 va = rnd(va, INITRND); 1418 1419 segdata.rwx = 06; 1420 segdata.vaddr = va; 1421 segdata.fileoff = va - segtext.vaddr + segtext.fileoff; 1422 segdata.filelen = 0; 1423 if(HEADTYPE == Hwindows) 1424 segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); 1425 if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32) 1426 segdata.fileoff = segtext.fileoff + segtext.filelen; 1427 data = nil; 1428 noptr = nil; 1429 bss = nil; 1430 noptrbss = nil; 1431 datarelro = nil; 1432 for(s=segdata.sect; s != nil; s=s->next) { 1433 vlen = s->len; 1434 if(s->next) 1435 vlen = s->next->vaddr - s->vaddr; 1436 s->vaddr = va; 1437 va += vlen; 1438 segdata.len = va - segdata.vaddr; 1439 if(strcmp(s->name, ".data") == 0) 1440 data = s; 1441 if(strcmp(s->name, ".noptrdata") == 0) 1442 noptr = s; 1443 if(strcmp(s->name, ".bss") == 0) 1444 bss = s; 1445 if(strcmp(s->name, ".noptrbss") == 0) 1446 noptrbss = s; 1447 if(strcmp(s->name, ".data.rel.ro") == 0) 1448 datarelro = s; 1449 } 1450 segdata.filelen = bss->vaddr - segdata.vaddr; 1451 1452 text = segtext.sect; 1453 rodata = text->next; 1454 typelink = rodata->next; 1455 symtab = typelink->next; 1456 pclntab = symtab->next; 1457 1458 for(sym = datap; sym != nil; sym = sym->next) { 1459 cursym = sym; 1460 if(sym->type < SNOPTRDATA) 1461 sym->value += rodata->vaddr; 1462 else 1463 sym->value += segdata.sect->vaddr; 1464 for(sub = sym->sub; sub != nil; sub = sub->sub) 1465 sub->value += sym->value; 1466 } 1467 1468 xdefine("text", STEXT, text->vaddr); 1469 xdefine("etext", STEXT, text->vaddr + text->len); 1470 xdefine("rodata", SRODATA, rodata->vaddr); 1471 xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); 1472 xdefine("typelink", SRODATA, typelink->vaddr); 1473 xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len); 1474 if(datarelro != nil) { 1475 xdefine("datarelro", SRODATA, datarelro->vaddr); 1476 xdefine("edatarelro", SRODATA, datarelro->vaddr + datarelro->len); 1477 } 1478 1479 sym = lookup("gcdata", 0); 1480 xdefine("egcdata", STYPE, symaddr(sym) + sym->size); 1481 lookup("egcdata", 0)->sect = sym->sect; 1482 1483 sym = lookup("gcbss", 0); 1484 xdefine("egcbss", STYPE, symaddr(sym) + sym->size); 1485 lookup("egcbss", 0)->sect = sym->sect; 1486 1487 xdefine("symtab", SRODATA, symtab->vaddr); 1488 xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); 1489 xdefine("pclntab", SRODATA, pclntab->vaddr); 1490 xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len); 1491 xdefine("noptrdata", SNOPTRDATA, noptr->vaddr); 1492 xdefine("enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); 1493 xdefine("bss", SBSS, bss->vaddr); 1494 xdefine("ebss", SBSS, bss->vaddr + bss->len); 1495 xdefine("data", SDATA, data->vaddr); 1496 xdefine("edata", SDATA, data->vaddr + data->len); 1497 xdefine("noptrbss", SNOPTRBSS, noptrbss->vaddr); 1498 xdefine("enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); 1499 xdefine("end", SBSS, segdata.vaddr + segdata.len); 1500 }