| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Mach-O file writing | |
| // http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html | |
| #include "l.h" | |
| #include "../ld/dwarf.h" | |
| #include "../ld/lib.h" | |
| #include "../ld/macho.h" | |
| static int macho64; | |
| static MachoHdr hdr; | |
| static MachoLoad *load; | |
| static MachoSeg seg[16]; | |
| static int nload, mload, nseg, ndebug, nsect; | |
| enum | |
| { | |
| SymKindLocal = 0, | |
| SymKindExtdef, | |
| SymKindUndef, | |
| NumSymKind | |
| }; | |
| static int nkind[NumSymKind]; | |
| static LSym** sortsym; | |
| static int nsortsym; | |
| // Amount of space left for adding load commands | |
| // that refer to dynamic libraries. Because these have | |
| // to go in the Mach-O header, we can't just pick a | |
| // "big enough" header size. The initial header is | |
| // one page, the non-dynamic library stuff takes | |
| // up about 1300 bytes; we overestimate that as 2k. | |
| static int load_budget = INITIAL_MACHO_HEADR - 2*1024; | |
| static void machodysymtab(void); | |
| void | |
| machoinit(void) | |
| { | |
| switch(thechar) { | |
| // 64-bit architectures | |
| case '6': | |
| macho64 = 1; | |
| break; | |
| // 32-bit architectures | |
| default: | |
| break; | |
| } | |
| } | |
| MachoHdr* | |
| getMachoHdr(void) | |
| { | |
| return &hdr; | |
| } | |
| MachoLoad* | |
| newMachoLoad(uint32 type, uint32 ndata) | |
| { | |
| MachoLoad *l; | |
| if(nload >= mload) { | |
| if(mload == 0) | |
| mload = 1; | |
| else | |
| mload *= 2; | |
| load = erealloc(load, mload*sizeof load[0]); | |
| } | |
| if(macho64 && (ndata & 1)) | |
| ndata++; | |
| l = &load[nload++]; | |
| l->type = type; | |
| l->ndata = ndata; | |
| l->data = mal(ndata*4); | |
| return l; | |
| } | |
| MachoSeg* | |
| newMachoSeg(char *name, int msect) | |
| { | |
| MachoSeg *s; | |
| if(nseg >= nelem(seg)) { | |
| diag("too many segs"); | |
| errorexit(); | |
| } | |
| s = &seg[nseg++]; | |
| s->name = name; | |
| s->msect = msect; | |
| s->sect = mal(msect*sizeof s->sect[0]); | |
| return s; | |
| } | |
| MachoSect* | |
| newMachoSect(MachoSeg *seg, char *name, char *segname) | |
| { | |
| MachoSect *s; | |
| if(seg->nsect >= seg->msect) { | |
| diag("too many sects in segment %s", seg->name); | |
| errorexit(); | |
| } | |
| s = &seg->sect[seg->nsect++]; | |
| s->name = name; | |
| s->segname = segname; | |
| nsect++; | |
| return s; | |
| } | |
| // Generic linking code. | |
| static char **dylib; | |
| static int ndylib; | |
| static vlong linkoff; | |
| int | |
| machowrite(void) | |
| { | |
| vlong o1; | |
| int loadsize; | |
| int i, j; | |
| MachoSeg *s; | |
| MachoSect *t; | |
| MachoLoad *l; | |
| o1 = cpos(); | |
| loadsize = 4*4*ndebug; | |
| for(i=0; i<nload; i++) | |
| loadsize += 4*(load[i].ndata+2); | |
| if(macho64) { | |
| loadsize += 18*4*nseg; | |
| loadsize += 20*4*nsect; | |
| } else { | |
| loadsize += 14*4*nseg; | |
| loadsize += 17*4*nsect; | |
| } | |
| if(macho64) | |
| LPUT(0xfeedfacf); | |
| else | |
| LPUT(0xfeedface); | |
| LPUT(hdr.cpu); | |
| LPUT(hdr.subcpu); | |
| if(linkmode == LinkExternal) | |
| LPUT(1); /* file type - mach object */ | |
| else | |
| LPUT(2); /* file type - mach executable */ | |
| LPUT(nload+nseg+ndebug); | |
| LPUT(loadsize); | |
| LPUT(1); /* flags - no undefines */ | |
| if(macho64) | |
| LPUT(0); /* reserved */ | |
| for(i=0; i<nseg; i++) { | |
| s = &seg[i]; | |
| if(macho64) { | |
| LPUT(25); /* segment 64 */ | |
| LPUT(72+80*s->nsect); | |
| strnput(s->name, 16); | |
| VPUT(s->vaddr); | |
| VPUT(s->vsize); | |
| VPUT(s->fileoffset); | |
| VPUT(s->filesize); | |
| LPUT(s->prot1); | |
| LPUT(s->prot2); | |
| LPUT(s->nsect); | |
| LPUT(s->flag); | |
| } else { | |
| LPUT(1); /* segment 32 */ | |
| LPUT(56+68*s->nsect); | |
| strnput(s->name, 16); | |
| LPUT(s->vaddr); | |
| LPUT(s->vsize); | |
| LPUT(s->fileoffset); | |
| LPUT(s->filesize); | |
| LPUT(s->prot1); | |
| LPUT(s->prot2); | |
| LPUT(s->nsect); | |
| LPUT(s->flag); | |
| } | |
| for(j=0; j<s->nsect; j++) { | |
| t = &s->sect[j]; | |
| if(macho64) { | |
| strnput(t->name, 16); | |
| strnput(t->segname, 16); | |
| VPUT(t->addr); | |
| VPUT(t->size); | |
| LPUT(t->off); | |
| LPUT(t->align); | |
| LPUT(t->reloc); | |
| LPUT(t->nreloc); | |
| LPUT(t->flag); | |
| LPUT(t->res1); /* reserved */ | |
| LPUT(t->res2); /* reserved */ | |
| LPUT(0); /* reserved */ | |
| } else { | |
| strnput(t->name, 16); | |
| strnput(t->segname, 16); | |
| LPUT(t->addr); | |
| LPUT(t->size); | |
| LPUT(t->off); | |
| LPUT(t->align); | |
| LPUT(t->reloc); | |
| LPUT(t->nreloc); | |
| LPUT(t->flag); | |
| LPUT(t->res1); /* reserved */ | |
| LPUT(t->res2); /* reserved */ | |
| } | |
| } | |
| } | |
| for(i=0; i<nload; i++) { | |
| l = &load[i]; | |
| LPUT(l->type); | |
| LPUT(4*(l->ndata+2)); | |
| for(j=0; j<l->ndata; j++) | |
| LPUT(l->data[j]); | |
| } | |
| return cpos() - o1; | |
| } | |
| void | |
| domacho(void) | |
| { | |
| LSym *s; | |
| if(debug['d']) | |
| return; | |
| // empirically, string table must begin with " \x00". | |
| s = linklookup(ctxt, ".machosymstr", 0); | |
| s->type = SMACHOSYMSTR; | |
| s->reachable = 1; | |
| adduint8(ctxt, s, ' '); | |
| adduint8(ctxt, s, '\0'); | |
| s = linklookup(ctxt, ".machosymtab", 0); | |
| s->type = SMACHOSYMTAB; | |
| s->reachable = 1; | |
| if(linkmode != LinkExternal) { | |
| s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub | |
| s->type = SMACHOPLT; | |
| s->reachable = 1; | |
| s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr | |
| s->type = SMACHOGOT; | |
| s->reachable = 1; | |
| s->align = 4; | |
| s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt | |
| s->type = SMACHOINDIRECTPLT; | |
| s->reachable = 1; | |
| s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got | |
| s->type = SMACHOINDIRECTGOT; | |
| s->reachable = 1; | |
| } | |
| } | |
| void | |
| machoadddynlib(char *lib) | |
| { | |
| // Will need to store the library name rounded up | |
| // and 24 bytes of header metadata. If not enough | |
| // space, grab another page of initial space at the | |
| // beginning of the output file. | |
| load_budget -= (strlen(lib)+7)/8*8 + 24; | |
| if(load_budget < 0) { | |
| HEADR += 4096; | |
| INITTEXT += 4096; | |
| load_budget += 4096; | |
| } | |
| if(ndylib%32 == 0) | |
| dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]); | |
| dylib[ndylib++] = lib; | |
| } | |
| static void | |
| machoshbits(MachoSeg *mseg, Section *sect, char *segname) | |
| { | |
| MachoSect *msect; | |
| char buf[40]; | |
| char *p; | |
| snprint(buf, sizeof buf, "__%s", sect->name+1); | |
| for(p=buf; *p; p++) | |
| if(*p == '.') | |
| *p = '_'; | |
| msect = newMachoSect(mseg, estrdup(buf), segname); | |
| if(sect->rellen > 0) { | |
| msect->reloc = sect->reloff; | |
| msect->nreloc = sect->rellen / 8; | |
| } | |
| while(1<<msect->align < sect->align) | |
| msect->align++; | |
| msect->addr = sect->vaddr; | |
| msect->size = sect->len; | |
| if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) { | |
| // data in file | |
| if(sect->len > sect->seg->vaddr + sect->seg->filelen - sect->vaddr) | |
| diag("macho cannot represent section %s crossing data and bss", sect->name); | |
| msect->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; | |
| } else { | |
| // zero fill | |
| msect->off = 0; | |
| msect->flag |= 1; | |
| } | |
| if(sect->rwx & 1) | |
| msect->flag |= 0x400; /* has instructions */ | |
| if(strcmp(sect->name, ".plt") == 0) { | |
| msect->name = "__symbol_stub1"; | |
| msect->flag = 0x80000408; /* only instructions, code, symbol stubs */ | |
| msect->res1 = 0;//nkind[SymKindLocal]; | |
| msect->res2 = 6; | |
| } | |
| if(strcmp(sect->name, ".got") == 0) { | |
| msect->name = "__nl_symbol_ptr"; | |
| msect->flag = 6; /* section with nonlazy symbol pointers */ | |
| msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ | |
| } | |
| } | |
| void | |
| asmbmacho(void) | |
| { | |
| vlong v, w; | |
| vlong va; | |
| int a, i; | |
| MachoHdr *mh; | |
| MachoSeg *ms; | |
| MachoLoad *ml; | |
| Section *sect; | |
| /* apple MACH */ | |
| va = INITTEXT - HEADR; | |
| mh = getMachoHdr(); | |
| switch(thechar){ | |
| default: | |
| diag("unknown mach architecture"); | |
| errorexit(); | |
| case '6': | |
| mh->cpu = MACHO_CPU_AMD64; | |
| mh->subcpu = MACHO_SUBCPU_X86; | |
| break; | |
| case '8': | |
| mh->cpu = MACHO_CPU_386; | |
| mh->subcpu = MACHO_SUBCPU_X86; | |
| break; | |
| } | |
| ms = nil; | |
| if(linkmode == LinkExternal) { | |
| /* segment for entire file */ | |
| ms = newMachoSeg("", 40); | |
| ms->fileoffset = segtext.fileoff; | |
| ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff; | |
| } | |
| /* segment for zero page */ | |
| if(linkmode != LinkExternal) { | |
| ms = newMachoSeg("__PAGEZERO", 0); | |
| ms->vsize = va; | |
| } | |
| /* text */ | |
| v = rnd(HEADR+segtext.len, INITRND); | |
| if(linkmode != LinkExternal) { | |
| ms = newMachoSeg("__TEXT", 20); | |
| ms->vaddr = va; | |
| ms->vsize = v; | |
| ms->fileoffset = 0; | |
| ms->filesize = v; | |
| ms->prot1 = 7; | |
| ms->prot2 = 5; | |
| } | |
| for(sect=segtext.sect; sect!=nil; sect=sect->next) | |
| machoshbits(ms, sect, "__TEXT"); | |
| /* data */ | |
| if(linkmode != LinkExternal) { | |
| w = segdata.len; | |
| ms = newMachoSeg("__DATA", 20); | |
| ms->vaddr = va+v; | |
| ms->vsize = w; | |
| ms->fileoffset = v; | |
| ms->filesize = segdata.filelen; | |
| ms->prot1 = 3; | |
| ms->prot2 = 3; | |
| } | |
| for(sect=segdata.sect; sect!=nil; sect=sect->next) | |
| machoshbits(ms, sect, "__DATA"); | |
| if(linkmode != LinkExternal) { | |
| switch(thechar) { | |
| default: | |
| diag("unknown macho architecture"); | |
| errorexit(); | |
| case '6': | |
| ml = newMachoLoad(5, 42+2); /* unix thread */ | |
| ml->data[0] = 4; /* thread type */ | |
| ml->data[1] = 42; /* word count */ | |
| ml->data[2+32] = entryvalue(); /* start pc */ | |
| ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l | |
| break; | |
| case '8': | |
| ml = newMachoLoad(5, 16+2); /* unix thread */ | |
| ml->data[0] = 1; /* thread type */ | |
| ml->data[1] = 16; /* word count */ | |
| ml->data[2+10] = entryvalue(); /* start pc */ | |
| break; | |
| } | |
| } | |
| if(!debug['d']) { | |
| LSym *s1, *s2, *s3, *s4; | |
| // must match domacholink below | |
| s1 = linklookup(ctxt, ".machosymtab", 0); | |
| s2 = linklookup(ctxt, ".linkedit.plt", 0); | |
| s3 = linklookup(ctxt, ".linkedit.got", 0); | |
| s4 = linklookup(ctxt, ".machosymstr", 0); | |
| if(linkmode != LinkExternal) { | |
| ms = newMachoSeg("__LINKEDIT", 0); | |
| ms->vaddr = va+v+rnd(segdata.len, INITRND); | |
| ms->vsize = s1->size + s2->size + s3->size + s4->size; | |
| ms->fileoffset = linkoff; | |
| ms->filesize = ms->vsize; | |
| ms->prot1 = 7; | |
| ms->prot2 = 3; | |
| } | |
| ml = newMachoLoad(2, 4); /* LC_SYMTAB */ | |
| ml->data[0] = linkoff; /* symoff */ | |
| ml->data[1] = nsortsym; /* nsyms */ | |
| ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */ | |
| ml->data[3] = s4->size; /* strsize */ | |
| machodysymtab(); | |
| if(linkmode != LinkExternal) { | |
| ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */ | |
| ml->data[0] = 12; /* offset to string */ | |
| strcpy((char*)&ml->data[1], "/usr/lib/dyld"); | |
| for(i=0; i<ndylib; i++) { | |
| ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */ | |
| ml->data[0] = 24; /* offset of string from beginning of load */ | |
| ml->data[1] = 0; /* time stamp */ | |
| ml->data[2] = 0; /* version */ | |
| ml->data[3] = 0; /* compatibility version */ | |
| strcpy((char*)&ml->data[4], dylib[i]); | |
| } | |
| } | |
| } | |
| // TODO: dwarf headers go in ms too | |
| if(!debug['s'] && linkmode != LinkExternal) | |
| dwarfaddmachoheaders(); | |
| a = machowrite(); | |
| if(a > HEADR) | |
| diag("HEADR too small: %d > %d", a, HEADR); | |
| } | |
| static int | |
| symkind(LSym *s) | |
| { | |
| if(s->type == SDYNIMPORT) | |
| return SymKindUndef; | |
| if(s->cgoexport) | |
| return SymKindExtdef; | |
| return SymKindLocal; | |
| } | |
| static void | |
| addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) | |
| { | |
| USED(name); | |
| USED(addr); | |
| USED(size); | |
| USED(ver); | |
| USED(gotype); | |
| if(s == nil) | |
| return; | |
| switch(type) { | |
| default: | |
| return; | |
| case 'D': | |
| case 'B': | |
| case 'T': | |
| break; | |
| } | |
| if(sortsym) { | |
| sortsym[nsortsym] = s; | |
| nkind[symkind(s)]++; | |
| } | |
| nsortsym++; | |
| } | |
| static int | |
| scmp(const void *p1, const void *p2) | |
| { | |
| LSym *s1, *s2; | |
| int k1, k2; | |
| s1 = *(LSym**)p1; | |
| s2 = *(LSym**)p2; | |
| k1 = symkind(s1); | |
| k2 = symkind(s2); | |
| if(k1 != k2) | |
| return k1 - k2; | |
| return strcmp(s1->extname, s2->extname); | |
| } | |
| static void | |
| machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) | |
| { | |
| LSym *s; | |
| genasmsym(put); | |
| for(s=ctxt->allsym; s; s=s->allsym) | |
| if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) | |
| if(s->reachable) | |
| put(s, nil, 'D', 0, 0, 0, nil); | |
| } | |
| void | |
| machosymorder(void) | |
| { | |
| int i; | |
| // On Mac OS X Mountain Lion, we must sort exported symbols | |
| // So we sort them here and pre-allocate dynid for them | |
| // See http://golang.org/issue/4029 | |
| for(i=0; i<ndynexp; i++) | |
| dynexp[i]->reachable = 1; | |
| machogenasmsym(addsym); | |
| sortsym = mal(nsortsym * sizeof sortsym[0]); | |
| nsortsym = 0; | |
| machogenasmsym(addsym); | |
| qsort(sortsym, nsortsym, sizeof sortsym[0], scmp); | |
| for(i=0; i<nsortsym; i++) | |
| sortsym[i]->dynid = i; | |
| } | |
| static void | |
| machosymtab(void) | |
| { | |
| int i; | |
| LSym *symtab, *symstr, *s, *o; | |
| char *p; | |
| symtab = linklookup(ctxt, ".machosymtab", 0); | |
| symstr = linklookup(ctxt, ".machosymstr", 0); | |
| for(i=0; i<nsortsym; i++) { | |
| s = sortsym[i]; | |
| adduint32(ctxt, symtab, symstr->size); | |
| // Only add _ to C symbols. Go symbols have dot in the name. | |
| if(strstr(s->extname, ".") == nil) | |
| adduint8(ctxt, symstr, '_'); | |
| // replace "·" as ".", because DTrace cannot handle it. | |
| if(strstr(s->extname, "·") == nil) { | |
| addstring(symstr, s->extname); | |
| } else { | |
| p = s->extname; | |
| while (*p++ != '\0') { | |
| if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) { | |
| adduint8(ctxt, symstr, '.'); | |
| p++; | |
| } else { | |
| adduint8(ctxt, symstr, *p); | |
| } | |
| } | |
| adduint8(ctxt, symstr, '\0'); | |
| } | |
| if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) { | |
| adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol | |
| adduint8(ctxt, symtab, 0); // no section | |
| adduint16(ctxt, symtab, 0); // desc | |
| adduintxx(ctxt, symtab, 0, PtrSize); // no value | |
| } else { | |
| if(s->cgoexport) | |
| adduint8(ctxt, symtab, 0x0f); | |
| else | |
| adduint8(ctxt, symtab, 0x0e); | |
| o = s; | |
| while(o->outer != nil) | |
| o = o->outer; | |
| if(o->sect == nil) { | |
| diag("missing section for %s", s->name); | |
| adduint8(ctxt, symtab, 0); | |
| } else | |
| adduint8(ctxt, symtab, o->sect->extnum); | |
| adduint16(ctxt, symtab, 0); // desc | |
| adduintxx(ctxt, symtab, symaddr(s), PtrSize); | |
| } | |
| } | |
| } | |
| static void | |
| machodysymtab(void) | |
| { | |
| int n; | |
| MachoLoad *ml; | |
| LSym *s1, *s2, *s3; | |
| ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ | |
| n = 0; | |
| ml->data[0] = n; /* ilocalsym */ | |
| ml->data[1] = nkind[SymKindLocal]; /* nlocalsym */ | |
| n += nkind[SymKindLocal]; | |
| ml->data[2] = n; /* iextdefsym */ | |
| ml->data[3] = nkind[SymKindExtdef]; /* nextdefsym */ | |
| n += nkind[SymKindExtdef]; | |
| ml->data[4] = n; /* iundefsym */ | |
| ml->data[5] = nkind[SymKindUndef]; /* nundefsym */ | |
| ml->data[6] = 0; /* tocoffset */ | |
| ml->data[7] = 0; /* ntoc */ | |
| ml->data[8] = 0; /* modtaboff */ | |
| ml->data[9] = 0; /* nmodtab */ | |
| ml->data[10] = 0; /* extrefsymoff */ | |
| ml->data[11] = 0; /* nextrefsyms */ | |
| // must match domacholink below | |
| s1 = linklookup(ctxt, ".machosymtab", 0); | |
| s2 = linklookup(ctxt, ".linkedit.plt", 0); | |
| s3 = linklookup(ctxt, ".linkedit.got", 0); | |
| ml->data[12] = linkoff + s1->size; /* indirectsymoff */ | |
| ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */ | |
| ml->data[14] = 0; /* extreloff */ | |
| ml->data[15] = 0; /* nextrel */ | |
| ml->data[16] = 0; /* locreloff */ | |
| ml->data[17] = 0; /* nlocrel */ | |
| } | |
| vlong | |
| domacholink(void) | |
| { | |
| int size; | |
| LSym *s1, *s2, *s3, *s4; | |
| machosymtab(); | |
| // write data that will be linkedit section | |
| s1 = linklookup(ctxt, ".machosymtab", 0); | |
| s2 = linklookup(ctxt, ".linkedit.plt", 0); | |
| s3 = linklookup(ctxt, ".linkedit.got", 0); | |
| s4 = linklookup(ctxt, ".machosymstr", 0); | |
| // Force the linkedit section to end on a 16-byte | |
| // boundary. This allows pure (non-cgo) Go binaries | |
| // to be code signed correctly. | |
| // | |
| // Apple's codesign_allocate (a helper utility for | |
| // the codesign utility) can do this fine itself if | |
| // it is run on a dynamic Mach-O binary. However, | |
| // when it is run on a pure (non-cgo) Go binary, where | |
| // the linkedit section is mostly empty, it fails to | |
| // account for the extra padding that it itself adds | |
| // when adding the LC_CODE_SIGNATURE load command | |
| // (which must be aligned on a 16-byte boundary). | |
| // | |
| // By forcing the linkedit section to end on a 16-byte | |
| // boundary, codesign_allocate will not need to apply | |
| // any alignment padding itself, working around the | |
| // issue. | |
| while(s4->size%16) | |
| adduint8(ctxt, s4, 0); | |
| size = s1->size + s2->size + s3->size + s4->size; | |
| if(size > 0) { | |
| linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND); | |
| cseek(linkoff); | |
| cwrite(s1->p, s1->size); | |
| cwrite(s2->p, s2->size); | |
| cwrite(s3->p, s3->size); | |
| cwrite(s4->p, s4->size); | |
| } | |
| return rnd(size, INITRND); | |
| } | |
| void | |
| machorelocsect(Section *sect, LSym *first) | |
| { | |
| LSym *sym; | |
| int32 eaddr; | |
| Reloc *r; | |
| // If main section has no bits, nothing to relocate. | |
| if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen) | |
| return; | |
| sect->reloff = cpos(); | |
| for(sym = first; sym != nil; sym = sym->next) { | |
| if(!sym->reachable) | |
| continue; | |
| if(sym->value >= sect->vaddr) | |
| break; | |
| } | |
| eaddr = sect->vaddr + sect->len; | |
| for(; sym != nil; sym = sym->next) { | |
| if(!sym->reachable) | |
| continue; | |
| if(sym->value >= eaddr) | |
| break; | |
| ctxt->cursym = sym; | |
| for(r = sym->r; r < sym->r+sym->nr; r++) { | |
| if(r->done) | |
| continue; | |
| if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0) | |
| diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name); | |
| } | |
| } | |
| sect->rellen = cpos() - sect->reloff; | |
| } | |
| void | |
| machoemitreloc(void) | |
| { | |
| Section *sect; | |
| while(cpos()&7) | |
| cput(0); | |
| machorelocsect(segtext.sect, ctxt->textp); | |
| for(sect=segtext.sect->next; sect!=nil; sect=sect->next) | |
| machorelocsect(sect, datap); | |
| for(sect=segdata.sect; sect!=nil; sect=sect->next) | |
| machorelocsect(sect, datap); | |
| } |