github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/cmd/ld/macho.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Mach-O file writing 6 // http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html 7 8 #include "l.h" 9 #include "../ld/dwarf.h" 10 #include "../ld/lib.h" 11 #include "../ld/macho.h" 12 13 static int macho64; 14 static MachoHdr hdr; 15 static MachoLoad *load; 16 static MachoSeg seg[16]; 17 static int nload, mload, nseg, ndebug, nsect; 18 19 enum 20 { 21 SymKindLocal = 0, 22 SymKindExtdef, 23 SymKindUndef, 24 NumSymKind 25 }; 26 27 static int nkind[NumSymKind]; 28 static LSym** sortsym; 29 static int nsortsym; 30 31 // Amount of space left for adding load commands 32 // that refer to dynamic libraries. Because these have 33 // to go in the Mach-O header, we can't just pick a 34 // "big enough" header size. The initial header is 35 // one page, the non-dynamic library stuff takes 36 // up about 1300 bytes; we overestimate that as 2k. 37 static int load_budget = INITIAL_MACHO_HEADR - 2*1024; 38 39 static void machodysymtab(void); 40 41 void 42 machoinit(void) 43 { 44 switch(thechar) { 45 // 64-bit architectures 46 case '6': 47 macho64 = 1; 48 break; 49 50 // 32-bit architectures 51 default: 52 break; 53 } 54 } 55 56 MachoHdr* 57 getMachoHdr(void) 58 { 59 return &hdr; 60 } 61 62 MachoLoad* 63 newMachoLoad(uint32 type, uint32 ndata) 64 { 65 MachoLoad *l; 66 67 if(nload >= mload) { 68 if(mload == 0) 69 mload = 1; 70 else 71 mload *= 2; 72 load = erealloc(load, mload*sizeof load[0]); 73 } 74 75 if(macho64 && (ndata & 1)) 76 ndata++; 77 78 l = &load[nload++]; 79 l->type = type; 80 l->ndata = ndata; 81 l->data = mal(ndata*4); 82 return l; 83 } 84 85 MachoSeg* 86 newMachoSeg(char *name, int msect) 87 { 88 MachoSeg *s; 89 90 if(nseg >= nelem(seg)) { 91 diag("too many segs"); 92 errorexit(); 93 } 94 s = &seg[nseg++]; 95 s->name = name; 96 s->msect = msect; 97 s->sect = mal(msect*sizeof s->sect[0]); 98 return s; 99 } 100 101 MachoSect* 102 newMachoSect(MachoSeg *seg, char *name, char *segname) 103 { 104 MachoSect *s; 105 106 if(seg->nsect >= seg->msect) { 107 diag("too many sects in segment %s", seg->name); 108 errorexit(); 109 } 110 s = &seg->sect[seg->nsect++]; 111 s->name = name; 112 s->segname = segname; 113 nsect++; 114 return s; 115 } 116 117 // Generic linking code. 118 119 static char **dylib; 120 static int ndylib; 121 122 static vlong linkoff; 123 124 int 125 machowrite(void) 126 { 127 vlong o1; 128 int loadsize; 129 int i, j; 130 MachoSeg *s; 131 MachoSect *t; 132 MachoLoad *l; 133 134 o1 = cpos(); 135 136 loadsize = 4*4*ndebug; 137 for(i=0; i<nload; i++) 138 loadsize += 4*(load[i].ndata+2); 139 if(macho64) { 140 loadsize += 18*4*nseg; 141 loadsize += 20*4*nsect; 142 } else { 143 loadsize += 14*4*nseg; 144 loadsize += 17*4*nsect; 145 } 146 147 if(macho64) 148 LPUT(0xfeedfacf); 149 else 150 LPUT(0xfeedface); 151 LPUT(hdr.cpu); 152 LPUT(hdr.subcpu); 153 if(linkmode == LinkExternal) 154 LPUT(1); /* file type - mach object */ 155 else 156 LPUT(2); /* file type - mach executable */ 157 LPUT(nload+nseg+ndebug); 158 LPUT(loadsize); 159 LPUT(1); /* flags - no undefines */ 160 if(macho64) 161 LPUT(0); /* reserved */ 162 163 for(i=0; i<nseg; i++) { 164 s = &seg[i]; 165 if(macho64) { 166 LPUT(25); /* segment 64 */ 167 LPUT(72+80*s->nsect); 168 strnput(s->name, 16); 169 VPUT(s->vaddr); 170 VPUT(s->vsize); 171 VPUT(s->fileoffset); 172 VPUT(s->filesize); 173 LPUT(s->prot1); 174 LPUT(s->prot2); 175 LPUT(s->nsect); 176 LPUT(s->flag); 177 } else { 178 LPUT(1); /* segment 32 */ 179 LPUT(56+68*s->nsect); 180 strnput(s->name, 16); 181 LPUT(s->vaddr); 182 LPUT(s->vsize); 183 LPUT(s->fileoffset); 184 LPUT(s->filesize); 185 LPUT(s->prot1); 186 LPUT(s->prot2); 187 LPUT(s->nsect); 188 LPUT(s->flag); 189 } 190 for(j=0; j<s->nsect; j++) { 191 t = &s->sect[j]; 192 if(macho64) { 193 strnput(t->name, 16); 194 strnput(t->segname, 16); 195 VPUT(t->addr); 196 VPUT(t->size); 197 LPUT(t->off); 198 LPUT(t->align); 199 LPUT(t->reloc); 200 LPUT(t->nreloc); 201 LPUT(t->flag); 202 LPUT(t->res1); /* reserved */ 203 LPUT(t->res2); /* reserved */ 204 LPUT(0); /* reserved */ 205 } else { 206 strnput(t->name, 16); 207 strnput(t->segname, 16); 208 LPUT(t->addr); 209 LPUT(t->size); 210 LPUT(t->off); 211 LPUT(t->align); 212 LPUT(t->reloc); 213 LPUT(t->nreloc); 214 LPUT(t->flag); 215 LPUT(t->res1); /* reserved */ 216 LPUT(t->res2); /* reserved */ 217 } 218 } 219 } 220 221 for(i=0; i<nload; i++) { 222 l = &load[i]; 223 LPUT(l->type); 224 LPUT(4*(l->ndata+2)); 225 for(j=0; j<l->ndata; j++) 226 LPUT(l->data[j]); 227 } 228 229 return cpos() - o1; 230 } 231 232 void 233 domacho(void) 234 { 235 LSym *s; 236 237 if(debug['d']) 238 return; 239 240 // empirically, string table must begin with " \x00". 241 s = linklookup(ctxt, ".machosymstr", 0); 242 s->type = SMACHOSYMSTR; 243 s->reachable = 1; 244 adduint8(ctxt, s, ' '); 245 adduint8(ctxt, s, '\0'); 246 247 s = linklookup(ctxt, ".machosymtab", 0); 248 s->type = SMACHOSYMTAB; 249 s->reachable = 1; 250 251 if(linkmode != LinkExternal) { 252 s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub 253 s->type = SMACHOPLT; 254 s->reachable = 1; 255 256 s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr 257 s->type = SMACHOGOT; 258 s->reachable = 1; 259 s->align = 4; 260 261 s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt 262 s->type = SMACHOINDIRECTPLT; 263 s->reachable = 1; 264 265 s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got 266 s->type = SMACHOINDIRECTGOT; 267 s->reachable = 1; 268 } 269 } 270 271 void 272 machoadddynlib(char *lib) 273 { 274 // Will need to store the library name rounded up 275 // and 24 bytes of header metadata. If not enough 276 // space, grab another page of initial space at the 277 // beginning of the output file. 278 load_budget -= (strlen(lib)+7)/8*8 + 24; 279 if(load_budget < 0) { 280 HEADR += 4096; 281 INITTEXT += 4096; 282 load_budget += 4096; 283 } 284 285 if(ndylib%32 == 0) 286 dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]); 287 dylib[ndylib++] = lib; 288 } 289 290 static void 291 machoshbits(MachoSeg *mseg, Section *sect, char *segname) 292 { 293 MachoSect *msect; 294 char buf[40]; 295 char *p; 296 297 snprint(buf, sizeof buf, "__%s", sect->name+1); 298 for(p=buf; *p; p++) 299 if(*p == '.') 300 *p = '_'; 301 302 msect = newMachoSect(mseg, estrdup(buf), segname); 303 if(sect->rellen > 0) { 304 msect->reloc = sect->reloff; 305 msect->nreloc = sect->rellen / 8; 306 } 307 308 while(1<<msect->align < sect->align) 309 msect->align++; 310 msect->addr = sect->vaddr; 311 msect->size = sect->len; 312 313 if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) { 314 // data in file 315 if(sect->len > sect->seg->vaddr + sect->seg->filelen - sect->vaddr) 316 diag("macho cannot represent section %s crossing data and bss", sect->name); 317 msect->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; 318 } else { 319 // zero fill 320 msect->off = 0; 321 msect->flag |= 1; 322 } 323 324 if(sect->rwx & 1) 325 msect->flag |= 0x400; /* has instructions */ 326 327 if(strcmp(sect->name, ".plt") == 0) { 328 msect->name = "__symbol_stub1"; 329 msect->flag = 0x80000408; /* only instructions, code, symbol stubs */ 330 msect->res1 = 0;//nkind[SymKindLocal]; 331 msect->res2 = 6; 332 } 333 334 if(strcmp(sect->name, ".got") == 0) { 335 msect->name = "__nl_symbol_ptr"; 336 msect->flag = 6; /* section with nonlazy symbol pointers */ 337 msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ 338 } 339 } 340 341 void 342 asmbmacho(void) 343 { 344 vlong v, w; 345 vlong va; 346 int a, i; 347 MachoHdr *mh; 348 MachoSeg *ms; 349 MachoLoad *ml; 350 Section *sect; 351 352 /* apple MACH */ 353 va = INITTEXT - HEADR; 354 mh = getMachoHdr(); 355 switch(thechar){ 356 default: 357 diag("unknown mach architecture"); 358 errorexit(); 359 case '6': 360 mh->cpu = MACHO_CPU_AMD64; 361 mh->subcpu = MACHO_SUBCPU_X86; 362 break; 363 case '8': 364 mh->cpu = MACHO_CPU_386; 365 mh->subcpu = MACHO_SUBCPU_X86; 366 break; 367 } 368 369 ms = nil; 370 if(linkmode == LinkExternal) { 371 /* segment for entire file */ 372 ms = newMachoSeg("", 40); 373 ms->fileoffset = segtext.fileoff; 374 ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff; 375 } 376 377 /* segment for zero page */ 378 if(linkmode != LinkExternal) { 379 ms = newMachoSeg("__PAGEZERO", 0); 380 ms->vsize = va; 381 } 382 383 /* text */ 384 v = rnd(HEADR+segtext.len, INITRND); 385 if(linkmode != LinkExternal) { 386 ms = newMachoSeg("__TEXT", 20); 387 ms->vaddr = va; 388 ms->vsize = v; 389 ms->fileoffset = 0; 390 ms->filesize = v; 391 ms->prot1 = 7; 392 ms->prot2 = 5; 393 } 394 395 for(sect=segtext.sect; sect!=nil; sect=sect->next) 396 machoshbits(ms, sect, "__TEXT"); 397 398 /* data */ 399 if(linkmode != LinkExternal) { 400 w = segdata.len; 401 ms = newMachoSeg("__DATA", 20); 402 ms->vaddr = va+v; 403 ms->vsize = w; 404 ms->fileoffset = v; 405 ms->filesize = segdata.filelen; 406 ms->prot1 = 3; 407 ms->prot2 = 3; 408 } 409 410 for(sect=segdata.sect; sect!=nil; sect=sect->next) 411 machoshbits(ms, sect, "__DATA"); 412 413 if(linkmode != LinkExternal) { 414 switch(thechar) { 415 default: 416 diag("unknown macho architecture"); 417 errorexit(); 418 case '6': 419 ml = newMachoLoad(5, 42+2); /* unix thread */ 420 ml->data[0] = 4; /* thread type */ 421 ml->data[1] = 42; /* word count */ 422 ml->data[2+32] = entryvalue(); /* start pc */ 423 ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l 424 break; 425 case '8': 426 ml = newMachoLoad(5, 16+2); /* unix thread */ 427 ml->data[0] = 1; /* thread type */ 428 ml->data[1] = 16; /* word count */ 429 ml->data[2+10] = entryvalue(); /* start pc */ 430 break; 431 } 432 } 433 434 if(!debug['d']) { 435 LSym *s1, *s2, *s3, *s4; 436 437 // must match domacholink below 438 s1 = linklookup(ctxt, ".machosymtab", 0); 439 s2 = linklookup(ctxt, ".linkedit.plt", 0); 440 s3 = linklookup(ctxt, ".linkedit.got", 0); 441 s4 = linklookup(ctxt, ".machosymstr", 0); 442 443 if(linkmode != LinkExternal) { 444 ms = newMachoSeg("__LINKEDIT", 0); 445 ms->vaddr = va+v+rnd(segdata.len, INITRND); 446 ms->vsize = s1->size + s2->size + s3->size + s4->size; 447 ms->fileoffset = linkoff; 448 ms->filesize = ms->vsize; 449 ms->prot1 = 7; 450 ms->prot2 = 3; 451 } 452 453 ml = newMachoLoad(2, 4); /* LC_SYMTAB */ 454 ml->data[0] = linkoff; /* symoff */ 455 ml->data[1] = nsortsym; /* nsyms */ 456 ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */ 457 ml->data[3] = s4->size; /* strsize */ 458 459 machodysymtab(); 460 461 if(linkmode != LinkExternal) { 462 ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */ 463 ml->data[0] = 12; /* offset to string */ 464 strcpy((char*)&ml->data[1], "/usr/lib/dyld"); 465 466 for(i=0; i<ndylib; i++) { 467 ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */ 468 ml->data[0] = 24; /* offset of string from beginning of load */ 469 ml->data[1] = 0; /* time stamp */ 470 ml->data[2] = 0; /* version */ 471 ml->data[3] = 0; /* compatibility version */ 472 strcpy((char*)&ml->data[4], dylib[i]); 473 } 474 } 475 } 476 477 // TODO: dwarf headers go in ms too 478 if(!debug['s'] && linkmode != LinkExternal) 479 dwarfaddmachoheaders(); 480 481 a = machowrite(); 482 if(a > HEADR) 483 diag("HEADR too small: %d > %d", a, HEADR); 484 } 485 486 static int 487 symkind(LSym *s) 488 { 489 if(s->type == SDYNIMPORT) 490 return SymKindUndef; 491 if(s->cgoexport) 492 return SymKindExtdef; 493 return SymKindLocal; 494 } 495 496 static void 497 addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) 498 { 499 USED(name); 500 USED(addr); 501 USED(size); 502 USED(ver); 503 USED(gotype); 504 505 if(s == nil) 506 return; 507 508 switch(type) { 509 default: 510 return; 511 case 'D': 512 case 'B': 513 case 'T': 514 break; 515 } 516 517 if(sortsym) { 518 sortsym[nsortsym] = s; 519 nkind[symkind(s)]++; 520 } 521 nsortsym++; 522 } 523 524 static int 525 scmp(const void *p1, const void *p2) 526 { 527 LSym *s1, *s2; 528 int k1, k2; 529 530 s1 = *(LSym**)p1; 531 s2 = *(LSym**)p2; 532 533 k1 = symkind(s1); 534 k2 = symkind(s2); 535 if(k1 != k2) 536 return k1 - k2; 537 538 return strcmp(s1->extname, s2->extname); 539 } 540 541 static void 542 machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) 543 { 544 LSym *s; 545 546 genasmsym(put); 547 for(s=ctxt->allsym; s; s=s->allsym) 548 if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) 549 if(s->reachable) 550 put(s, nil, 'D', 0, 0, 0, nil); 551 } 552 553 void 554 machosymorder(void) 555 { 556 int i; 557 558 // On Mac OS X Mountain Lion, we must sort exported symbols 559 // So we sort them here and pre-allocate dynid for them 560 // See http://golang.org/issue/4029 561 for(i=0; i<ndynexp; i++) 562 dynexp[i]->reachable = 1; 563 machogenasmsym(addsym); 564 sortsym = mal(nsortsym * sizeof sortsym[0]); 565 nsortsym = 0; 566 machogenasmsym(addsym); 567 qsort(sortsym, nsortsym, sizeof sortsym[0], scmp); 568 for(i=0; i<nsortsym; i++) 569 sortsym[i]->dynid = i; 570 } 571 572 static void 573 machosymtab(void) 574 { 575 int i; 576 LSym *symtab, *symstr, *s, *o; 577 char *p; 578 579 symtab = linklookup(ctxt, ".machosymtab", 0); 580 symstr = linklookup(ctxt, ".machosymstr", 0); 581 582 for(i=0; i<nsortsym; i++) { 583 s = sortsym[i]; 584 adduint32(ctxt, symtab, symstr->size); 585 586 // Only add _ to C symbols. Go symbols have dot in the name. 587 if(strstr(s->extname, ".") == nil) 588 adduint8(ctxt, symstr, '_'); 589 // replace "·" as ".", because DTrace cannot handle it. 590 if(strstr(s->extname, "·") == nil) { 591 addstring(symstr, s->extname); 592 } else { 593 for(p = s->extname; *p; p++) { 594 if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) { 595 adduint8(ctxt, symstr, '.'); 596 p++; 597 } else { 598 adduint8(ctxt, symstr, *p); 599 } 600 } 601 adduint8(ctxt, symstr, '\0'); 602 } 603 if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) { 604 adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol 605 adduint8(ctxt, symtab, 0); // no section 606 adduint16(ctxt, symtab, 0); // desc 607 adduintxx(ctxt, symtab, 0, PtrSize); // no value 608 } else { 609 if(s->cgoexport) 610 adduint8(ctxt, symtab, 0x0f); 611 else 612 adduint8(ctxt, symtab, 0x0e); 613 o = s; 614 while(o->outer != nil) 615 o = o->outer; 616 if(o->sect == nil) { 617 diag("missing section for %s", s->name); 618 adduint8(ctxt, symtab, 0); 619 } else 620 adduint8(ctxt, symtab, o->sect->extnum); 621 adduint16(ctxt, symtab, 0); // desc 622 adduintxx(ctxt, symtab, symaddr(s), PtrSize); 623 } 624 } 625 } 626 627 static void 628 machodysymtab(void) 629 { 630 int n; 631 MachoLoad *ml; 632 LSym *s1, *s2, *s3; 633 634 ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ 635 636 n = 0; 637 ml->data[0] = n; /* ilocalsym */ 638 ml->data[1] = nkind[SymKindLocal]; /* nlocalsym */ 639 n += nkind[SymKindLocal]; 640 641 ml->data[2] = n; /* iextdefsym */ 642 ml->data[3] = nkind[SymKindExtdef]; /* nextdefsym */ 643 n += nkind[SymKindExtdef]; 644 645 ml->data[4] = n; /* iundefsym */ 646 ml->data[5] = nkind[SymKindUndef]; /* nundefsym */ 647 648 ml->data[6] = 0; /* tocoffset */ 649 ml->data[7] = 0; /* ntoc */ 650 ml->data[8] = 0; /* modtaboff */ 651 ml->data[9] = 0; /* nmodtab */ 652 ml->data[10] = 0; /* extrefsymoff */ 653 ml->data[11] = 0; /* nextrefsyms */ 654 655 // must match domacholink below 656 s1 = linklookup(ctxt, ".machosymtab", 0); 657 s2 = linklookup(ctxt, ".linkedit.plt", 0); 658 s3 = linklookup(ctxt, ".linkedit.got", 0); 659 ml->data[12] = linkoff + s1->size; /* indirectsymoff */ 660 ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */ 661 662 ml->data[14] = 0; /* extreloff */ 663 ml->data[15] = 0; /* nextrel */ 664 ml->data[16] = 0; /* locreloff */ 665 ml->data[17] = 0; /* nlocrel */ 666 } 667 668 vlong 669 domacholink(void) 670 { 671 int size; 672 LSym *s1, *s2, *s3, *s4; 673 674 machosymtab(); 675 676 // write data that will be linkedit section 677 s1 = linklookup(ctxt, ".machosymtab", 0); 678 s2 = linklookup(ctxt, ".linkedit.plt", 0); 679 s3 = linklookup(ctxt, ".linkedit.got", 0); 680 s4 = linklookup(ctxt, ".machosymstr", 0); 681 682 // Force the linkedit section to end on a 16-byte 683 // boundary. This allows pure (non-cgo) Go binaries 684 // to be code signed correctly. 685 // 686 // Apple's codesign_allocate (a helper utility for 687 // the codesign utility) can do this fine itself if 688 // it is run on a dynamic Mach-O binary. However, 689 // when it is run on a pure (non-cgo) Go binary, where 690 // the linkedit section is mostly empty, it fails to 691 // account for the extra padding that it itself adds 692 // when adding the LC_CODE_SIGNATURE load command 693 // (which must be aligned on a 16-byte boundary). 694 // 695 // By forcing the linkedit section to end on a 16-byte 696 // boundary, codesign_allocate will not need to apply 697 // any alignment padding itself, working around the 698 // issue. 699 while(s4->size%16) 700 adduint8(ctxt, s4, 0); 701 702 size = s1->size + s2->size + s3->size + s4->size; 703 704 if(size > 0) { 705 linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND); 706 cseek(linkoff); 707 708 cwrite(s1->p, s1->size); 709 cwrite(s2->p, s2->size); 710 cwrite(s3->p, s3->size); 711 cwrite(s4->p, s4->size); 712 } 713 714 return rnd(size, INITRND); 715 } 716 717 718 void 719 machorelocsect(Section *sect, LSym *first) 720 { 721 LSym *sym; 722 int32 eaddr; 723 Reloc *r; 724 725 // If main section has no bits, nothing to relocate. 726 if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen) 727 return; 728 729 sect->reloff = cpos(); 730 for(sym = first; sym != nil; sym = sym->next) { 731 if(!sym->reachable) 732 continue; 733 if(sym->value >= sect->vaddr) 734 break; 735 } 736 737 eaddr = sect->vaddr + sect->len; 738 for(; sym != nil; sym = sym->next) { 739 if(!sym->reachable) 740 continue; 741 if(sym->value >= eaddr) 742 break; 743 ctxt->cursym = sym; 744 745 for(r = sym->r; r < sym->r+sym->nr; r++) { 746 if(r->done) 747 continue; 748 if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0) 749 diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name); 750 } 751 } 752 753 sect->rellen = cpos() - sect->reloff; 754 } 755 756 void 757 machoemitreloc(void) 758 { 759 Section *sect; 760 761 while(cpos()&7) 762 cput(0); 763 764 machorelocsect(segtext.sect, ctxt->textp); 765 for(sect=segtext.sect->next; sect!=nil; sect=sect->next) 766 machorelocsect(sect, datap); 767 for(sect=segdata.sect; sect!=nil; sect=sect->next) 768 machorelocsect(sect, datap); 769 }