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