summaryrefslogtreecommitdiff
path: root/src/cmd/ld/macho.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld/macho.c')
-rw-r--r--src/cmd/ld/macho.c592
1 files changed, 406 insertions, 186 deletions
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 6781c25a4..d135a92da 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -14,9 +14,20 @@ static int macho64;
static MachoHdr hdr;
static MachoLoad *load;
static MachoSeg seg[16];
-static MachoDebug xdebug[16];
static int nload, mload, nseg, ndebug, nsect;
+enum
+{
+ SymKindLocal = 0,
+ SymKindExtdef,
+ SymKindUndef,
+ NumSymKind
+};
+
+static int nkind[NumSymKind];
+static Sym** 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
@@ -25,6 +36,8 @@ static int nload, mload, nseg, ndebug, nsect;
// 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)
{
@@ -56,11 +69,7 @@ newMachoLoad(uint32 type, uint32 ndata)
mload = 1;
else
mload *= 2;
- load = realloc(load, mload*sizeof load[0]);
- if(load == nil) {
- diag("out of memory");
- errorexit();
- }
+ load = erealloc(load, mload*sizeof load[0]);
}
if(macho64 && (ndata & 1))
@@ -90,7 +99,7 @@ newMachoSeg(char *name, int msect)
}
MachoSect*
-newMachoSect(MachoSeg *seg, char *name)
+newMachoSect(MachoSeg *seg, char *name, char *segname)
{
MachoSect *s;
@@ -100,21 +109,11 @@ newMachoSect(MachoSeg *seg, char *name)
}
s = &seg->sect[seg->nsect++];
s->name = name;
+ s->segname = segname;
nsect++;
return s;
}
-MachoDebug*
-newMachoDebug(void)
-{
- if(ndebug >= nelem(xdebug)) {
- diag("too many debugs");
- errorexit();
- }
- return &xdebug[ndebug++];
-}
-
-
// Generic linking code.
static char **dylib;
@@ -130,7 +129,6 @@ machowrite(void)
int i, j;
MachoSeg *s;
MachoSect *t;
- MachoDebug *d;
MachoLoad *l;
o1 = cpos();
@@ -152,7 +150,10 @@ machowrite(void)
LPUT(0xfeedface);
LPUT(hdr.cpu);
LPUT(hdr.subcpu);
- LPUT(2); /* file type - mach executable */
+ 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 */
@@ -190,7 +191,7 @@ machowrite(void)
t = &s->sect[j];
if(macho64) {
strnput(t->name, 16);
- strnput(s->name, 16);
+ strnput(t->segname, 16);
VPUT(t->addr);
VPUT(t->size);
LPUT(t->off);
@@ -203,7 +204,7 @@ machowrite(void)
LPUT(0); /* reserved */
} else {
strnput(t->name, 16);
- strnput(s->name, 16);
+ strnput(t->segname, 16);
LPUT(t->addr);
LPUT(t->size);
LPUT(t->off);
@@ -225,14 +226,6 @@ machowrite(void)
LPUT(l->data[j]);
}
- for(i=0; i<ndebug; i++) {
- d = &xdebug[i];
- LPUT(3); /* obsolete gdb debug info */
- LPUT(16); /* size of symseg command */
- LPUT(d->fileoffset);
- LPUT(d->filesize);
- }
-
return cpos() - o1;
}
@@ -245,31 +238,34 @@ domacho(void)
return;
// empirically, string table must begin with " \x00".
- s = lookup(".dynstr", 0);
- s->type = SMACHODYNSTR;
+ s = lookup(".machosymstr", 0);
+ s->type = SMACHOSYMSTR;
s->reachable = 1;
adduint8(s, ' ');
adduint8(s, '\0');
- s = lookup(".dynsym", 0);
- s->type = SMACHODYNSYM;
+ s = lookup(".machosymtab", 0);
+ s->type = SMACHOSYMTAB;
s->reachable = 1;
- s = lookup(".plt", 0); // will be __symbol_stub
- s->type = SMACHOPLT;
- s->reachable = 1;
+ if(linkmode != LinkExternal) {
+ s = lookup(".plt", 0); // will be __symbol_stub
+ s->type = SMACHOPLT;
+ s->reachable = 1;
- s = lookup(".got", 0); // will be __nl_symbol_ptr
- s->type = SMACHOGOT;
- s->reachable = 1;
+ s = lookup(".got", 0); // will be __nl_symbol_ptr
+ s->type = SMACHOGOT;
+ s->reachable = 1;
+ s->align = 4;
- s = lookup(".linkedit.plt", 0); // indirect table for .plt
- s->type = SMACHOINDIRECTPLT;
- s->reachable = 1;
+ s = lookup(".linkedit.plt", 0); // indirect table for .plt
+ s->type = SMACHOINDIRECTPLT;
+ s->reachable = 1;
- s = lookup(".linkedit.got", 0); // indirect table for .got
- s->type = SMACHOINDIRECTGOT;
- s->reachable = 1;
+ s = lookup(".linkedit.got", 0); // indirect table for .got
+ s->type = SMACHOINDIRECTGOT;
+ s->reachable = 1;
+ }
}
void
@@ -286,16 +282,62 @@ machoadddynlib(char *lib)
load_budget += 4096;
}
- if(ndylib%32 == 0) {
- dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
- if(dylib == nil) {
- diag("out of memory");
- errorexit();
- }
- }
+ 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 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
+ }
+}
+
void
asmbmacho(void)
{
@@ -303,11 +345,9 @@ asmbmacho(void)
vlong va;
int a, i;
MachoHdr *mh;
- MachoSect *msect;
MachoSeg *ms;
- MachoDebug *md;
MachoLoad *ml;
- Sym *s;
+ Section *sect;
/* apple MACH */
va = INITTEXT - HEADR;
@@ -325,179 +365,305 @@ asmbmacho(void)
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 */
- ms = newMachoSeg("__PAGEZERO", 0);
- ms->vsize = va;
+ if(linkmode != LinkExternal) {
+ ms = newMachoSeg("__PAGEZERO", 0);
+ ms->vsize = va;
+ }
/* text */
v = rnd(HEADR+segtext.len, INITRND);
- ms = newMachoSeg("__TEXT", 2);
- ms->vaddr = va;
- ms->vsize = v;
- ms->filesize = v;
- ms->prot1 = 7;
- ms->prot2 = 5;
-
- msect = newMachoSect(ms, "__text");
- msect->addr = INITTEXT;
- msect->size = segtext.sect->len;
- msect->off = INITTEXT - va;
- msect->flag = 0x400; /* flag - some instructions */
-
- s = lookup(".plt", 0);
- if(s->size > 0) {
- msect = newMachoSect(ms, "__symbol_stub1");
- msect->addr = symaddr(s);
- msect->size = s->size;
- msect->off = ms->fileoffset + msect->addr - ms->vaddr;
- msect->flag = 0x80000408; /* flag */
- msect->res1 = 0; /* index into indirect symbol table */
- msect->res2 = 6; /* size of stubs */
+ 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 */
- w = segdata.len;
- ms = newMachoSeg("__DATA", 3);
- ms->vaddr = va+v;
- ms->vsize = w;
- ms->fileoffset = v;
- ms->filesize = segdata.filelen;
- ms->prot1 = 7;
- ms->prot2 = 3;
-
- msect = newMachoSect(ms, "__data");
- msect->addr = va+v;
- msect->off = v;
- msect->size = segdata.filelen;
-
- s = lookup(".got", 0);
- if(s->size > 0) {
- msect->size = symaddr(s) - msect->addr;
-
- msect = newMachoSect(ms, "__nl_symbol_ptr");
- msect->addr = symaddr(s);
- msect->size = s->size;
- msect->off = datoff(msect->addr);
- msect->align = 2;
- msect->flag = 6; /* section with nonlazy symbol pointers */
- msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
+ 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;
}
- msect = newMachoSect(ms, "__bss");
- msect->addr = va+v+segdata.filelen;
- msect->size = segdata.len - segdata.filelen;
- msect->flag = 1; /* flag - zero fill */
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ machoshbits(ms, sect, "__DATA");
- 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(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']) {
Sym *s1, *s2, *s3, *s4;
// must match domacholink below
- s1 = lookup(".dynsym", 0);
+ s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".dynstr", 0);
-
- 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;
+ s4 = lookup(".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] = s1->size / (macho64 ? 16 : 12); /* nsyms */
+ ml->data[1] = nsortsym; /* nsyms */
ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */
ml->data[3] = s4->size; /* strsize */
- ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
- ml->data[0] = 0; /* ilocalsym */
- ml->data[1] = 0; /* nlocalsym */
- ml->data[2] = 0; /* iextdefsym */
- ml->data[3] = ndynexp; /* nextdefsym */
- ml->data[4] = ndynexp; /* iundefsym */
- ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* 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 */
- 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 */
-
- 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]);
+ 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]);
+ }
}
}
- if(!debug['s']) {
- Sym *s;
-
- md = newMachoDebug();
- s = lookup("symtab", 0);
- md->fileoffset = datoff(s->value);
- md->filesize = s->size;
-
- md = newMachoDebug();
- s = lookup("pclntab", 0);
- md->fileoffset = datoff(s->value);
- md->filesize = s->size;
-
+ // 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(Sym *s)
+{
+ if(s->type == SDYNIMPORT)
+ return SymKindUndef;
+ if(s->cgoexport)
+ return SymKindExtdef;
+ return SymKindLocal;
+}
+
+static void
+addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *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)
+{
+ Sym *s1, *s2;
+ int k1, k2;
+
+ s1 = *(Sym**)p1;
+ s2 = *(Sym**)p2;
+
+ k1 = symkind(s1);
+ k2 = symkind(s2);
+ if(k1 != k2)
+ return k1 - k2;
+
+ return strcmp(s1->extname, s2->extname);
+}
+
+static void
+machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Sym *s;
+
+ genasmsym(put);
+ for(s=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;
+ Sym *symtab, *symstr, *s, *o;
+
+ symtab = lookup(".machosymtab", 0);
+ symstr = lookup(".machosymstr", 0);
+
+ for(i=0; i<nsortsym; i++) {
+ s = sortsym[i];
+ adduint32(symtab, symstr->size);
+
+ // Only add _ to C symbols. Go symbols have dot in the name.
+ if(strstr(s->extname, ".") == nil)
+ adduint8(symstr, '_');
+ addstring(symstr, s->extname);
+ if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) {
+ adduint8(symtab, 0x01); // type N_EXT, external symbol
+ adduint8(symtab, 0); // no section
+ adduint16(symtab, 0); // desc
+ adduintxx(symtab, 0, PtrSize); // no value
+ } else {
+ if(s->cgoexport)
+ adduint8(symtab, 0x0f);
+ else
+ adduint8(symtab, 0x0e);
+ o = s;
+ while(o->outer != nil)
+ o = o->outer;
+ if(o->sect == nil) {
+ diag("missing section for %s", s->name);
+ adduint8(symtab, 0);
+ } else
+ adduint8(symtab, o->sect->extnum);
+ adduint16(symtab, 0); // desc
+ adduintxx(symtab, symaddr(s), PtrSize);
+ }
+ }
+}
+
+static void
+machodysymtab(void)
+{
+ int n;
+ MachoLoad *ml;
+ Sym *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 = lookup(".machosymtab", 0);
+ s2 = lookup(".linkedit.plt", 0);
+ s3 = lookup(".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;
Sym *s1, *s2, *s3, *s4;
+ machosymtab();
+
// write data that will be linkedit section
- s1 = lookup(".dynsym", 0);
- relocsym(s1);
+ s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".dynstr", 0);
+ s4 = lookup(".machosymstr", 0);
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@@ -533,3 +699,57 @@ domacholink(void)
return rnd(size, INITRND);
}
+
+
+void
+machorelocsect(Section *sect, Sym *first)
+{
+ Sym *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;
+ 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, 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);
+}