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.c321
1 files changed, 321 insertions, 0 deletions
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 159aceb9e..e4fe963ac 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -92,6 +92,22 @@ newMachoDebug(void)
return &xdebug[ndebug++];
}
+
+// Generic linking code.
+
+static uchar *linkdata;
+static uint32 nlinkdata;
+static uint32 mlinkdata;
+
+static uchar *strtab;
+static uint32 nstrtab;
+static uint32 mstrtab;
+
+static char **dylib;
+static int ndylib;
+
+static vlong linkoff;
+
int
machowrite(void)
{
@@ -205,3 +221,308 @@ machowrite(void)
return Boffset(&bso) - o1;
}
+
+static void*
+grow(uchar **dat, uint32 *ndat, uint32 *mdat, uint32 n)
+{
+ uchar *p;
+ uint32 old;
+
+ if(*ndat+n > *mdat) {
+ old = *mdat;
+ *mdat = (*ndat+n)*2 + 128;
+ *dat = realloc(*dat, *mdat);
+ if(*dat == 0) {
+ diag("out of memory");
+ errorexit();
+ }
+ memset(*dat+old, 0, *mdat-old);
+ }
+ p = *dat + *ndat;
+ *ndat += n;
+ return p;
+}
+
+static int
+needlib(char *name)
+{
+ char *p;
+ Sym *s;
+
+ /* reuse hash code in symbol table */
+ p = smprint(".machoload.%s", name);
+ s = lookup(p, 0);
+ if(s->type == 0) {
+ s->type = 100; // avoid SDATA, etc.
+ return 1;
+ }
+ return 0;
+}
+
+void
+domacho(void)
+{
+ int h, nsym, ptrsize;
+ char *p;
+ uchar *dat;
+ uint32 x;
+ Sym *s;
+
+ ptrsize = 4;
+ if(macho64)
+ ptrsize = 8;
+
+ // empirically, string table must begin with " \x00".
+ if(!debug['d'])
+ *(char*)grow(&strtab, &nstrtab, &mstrtab, 2) = ' ';
+
+ nsym = 0;
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->link) {
+ if(!s->reachable || (s->type != SDATA && s->type != SBSS) || s->dynldname == nil)
+ continue;
+ if(debug['d']) {
+ diag("cannot use dynamic loading and -d");
+ errorexit();
+ }
+ s->type = SMACHO;
+ s->value = nsym*ptrsize;
+
+ /* symbol table entry - darwin still puts _ prefixes on all C symbols */
+ x = nstrtab;
+ p = grow(&strtab, &nstrtab, &mstrtab, 1+strlen(s->dynldname)+1);
+ *p++ = '_';
+ strcpy(p, s->dynldname);
+
+ dat = grow(&linkdata, &nlinkdata, &mlinkdata, 8+ptrsize);
+ dat[0] = x;
+ dat[1] = x>>8;
+ dat[2] = x>>16;
+ dat[3] = x>>24;
+ dat[4] = 0x01; // type: N_EXT - external symbol
+
+ if(needlib(s->dynldlib)) {
+ if(ndylib%32 == 0) {
+ dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
+ if(dylib == nil) {
+ diag("out of memory");
+ errorexit();
+ }
+ }
+ dylib[ndylib++] = s->dynldlib;
+ }
+ nsym++;
+ }
+ }
+
+ /*
+ * list of symbol table indexes.
+ * we don't take advantage of the opportunity
+ * to order the symbol table differently from
+ * this list, so it is boring: 0 1 2 3 4 ...
+ */
+ for(x=0; x<nsym; x++) {
+ dat = grow(&linkdata, &nlinkdata, &mlinkdata, 4);
+ dat[0] = x;
+ dat[1] = x>>8;
+ dat[2] = x>>16;
+ dat[3] = x>>24;
+ }
+
+ dynptrsize = nsym*ptrsize;
+}
+
+vlong
+domacholink(void)
+{
+ linkoff = 0;
+ if(nlinkdata > 0) {
+ linkoff = rnd(HEADR+textsize, INITRND) + rnd(datsize, INITRND);
+ seek(cout, linkoff, 0);
+ write(cout, linkdata, nlinkdata);
+ write(cout, strtab, nstrtab);
+ }
+ return rnd(nlinkdata+nstrtab, INITRND);
+}
+
+void
+asmbmacho(vlong symdatva, vlong symo)
+{
+ vlong v, w;
+ vlong va;
+ int a, i, ptrsize;
+ MachoHdr *mh;
+ MachoSect *msect;
+ MachoSeg *ms;
+ MachoDebug *md;
+ MachoLoad *ml;
+
+ /* 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;
+ ptrsize = 8;
+ break;
+ case '8':
+ mh->cpu = MACHO_CPU_386;
+ mh->subcpu = MACHO_SUBCPU_X86;
+ ptrsize = 4;
+ break;
+ }
+
+ /* segment for zero page */
+ ms = newMachoSeg("__PAGEZERO", 0);
+ ms->vsize = va;
+
+ /* text */
+ v = rnd(HEADR+textsize, INITRND);
+ ms = newMachoSeg("__TEXT", 1);
+ ms->vaddr = va;
+ ms->vsize = v;
+ ms->filesize = v;
+ ms->prot1 = 7;
+ ms->prot2 = 5;
+
+ msect = newMachoSect(ms, "__text");
+ msect->addr = INITTEXT;
+ msect->size = textsize;
+ msect->off = INITTEXT - va;
+ msect->flag = 0x400; /* flag - some instructions */
+
+ /* data */
+ w = datsize+dynptrsize+bsssize;
+ ms = newMachoSeg("__DATA", 2+(dynptrsize>0));
+ ms->vaddr = va+v;
+ ms->vsize = w;
+ ms->fileoffset = v;
+ ms->filesize = datsize;
+ ms->prot1 = 7;
+ ms->prot2 = 3;
+
+ msect = newMachoSect(ms, "__data");
+ msect->addr = va+v;
+ msect->size = datsize;
+ msect->off = v;
+
+ if(dynptrsize > 0) {
+ msect = newMachoSect(ms, "__nl_symbol_ptr");
+ msect->addr = va+v+datsize;
+ msect->size = dynptrsize;
+ msect->align = 2;
+ msect->flag = 6; /* section with nonlazy symbol pointers */
+ /*
+ * The reserved1 field is supposed to be the index of
+ * the first entry in the list of symbol table indexes
+ * in isymtab for the symbols we need. We only use
+ * pointers, so we need the entire list, so the index
+ * here should be 0, which luckily is what the Mach-O
+ * writing code emits by default for this not really reserved field.
+ msect->reserved1 = 0; - first indirect symbol table entry we need
+ */
+ }
+
+ msect = newMachoSect(ms, "__bss");
+ msect->addr = va+v+datsize+dynptrsize;
+ msect->size = bsssize;
+ msect->flag = 1; /* flag - zero fill */
+
+ 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()>>32;
+ 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']) {
+ int nsym;
+
+ nsym = dynptrsize/ptrsize;
+
+ ms = newMachoSeg("__LINKEDIT", 0);
+ ms->vaddr = va+v+rnd(datsize+dynptrsize+bsssize, INITRND);
+ ms->vsize = nlinkdata+nstrtab;
+ ms->fileoffset = linkoff;
+ ms->filesize = nlinkdata+nstrtab;
+ ms->prot1 = 7;
+ ms->prot2 = 3;
+
+ ml = newMachoLoad(2, 4); /* LC_SYMTAB */
+ ml->data[0] = linkoff; /* symoff */
+ ml->data[1] = nsym; /* nsyms */
+ ml->data[2] = linkoff + nlinkdata; /* stroff */
+ ml->data[3] = nstrtab; /* 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] = 0; /* nextdefsym */
+ ml->data[4] = 0; /* iundefsym */
+ ml->data[5] = nsym; /* 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 + nlinkdata - nsym*4; /* indirectsymoff */
+ ml->data[13] = nsym; /* 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]);
+ }
+ }
+
+ if(!debug['s']) {
+ ms = newMachoSeg("__SYMDAT", 1);
+ ms->vaddr = symdatva;
+ ms->vsize = 8+symsize+lcsize;
+ ms->fileoffset = symo;
+ ms->filesize = 8+symsize+lcsize;
+ ms->prot1 = 7;
+ ms->prot2 = 5;
+
+ md = newMachoDebug();
+ md->fileoffset = symo+8;
+ md->filesize = symsize;
+
+ md = newMachoDebug();
+ md->fileoffset = symo+8+symsize;
+ md->filesize = lcsize;
+ }
+
+ a = machowrite();
+ if(a > MACHORESERVE)
+ diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE);
+}