diff options
| author | Russ Cox <rsc@golang.org> | 2010-12-08 13:56:43 -0500 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2010-12-08 13:56:43 -0500 |
| commit | f5690004c2f5a5e478b66c2390d7ddba96cd7291 (patch) | |
| tree | 32d33548e9b7a1a35248a315af8cec95c7e9fa22 /src/cmd/ld | |
| parent | 9042c2ce6840a7679739e6ec6ff59b57db30c459 (diff) | |
| download | go-f5690004c2f5a5e478b66c2390d7ddba96cd7291.tar.xz | |
6l, 8l: support for linking ELF and Mach-O .o files
More support for references to dynamic symbols,
including full GOT and PLT for ELF objects.
For Mach-O everything ends up in the GOT: dealing
with the real lazy PLT is too hard for now so we punt.
R=iant, iant2
CC=golang-dev
https://golang.org/cl/3491042
Diffstat (limited to 'src/cmd/ld')
| -rw-r--r-- | src/cmd/ld/data.c | 158 | ||||
| -rw-r--r-- | src/cmd/ld/elf.c | 40 | ||||
| -rw-r--r-- | src/cmd/ld/go.c | 23 | ||||
| -rw-r--r-- | src/cmd/ld/lib.c | 92 | ||||
| -rw-r--r-- | src/cmd/ld/lib.h | 26 | ||||
| -rw-r--r-- | src/cmd/ld/macho.c | 353 | ||||
| -rw-r--r-- | src/cmd/ld/macho.h | 16 |
7 files changed, 416 insertions, 292 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index f2081178c0..c1e455c340 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -35,6 +35,8 @@ #include "../ld/elf.h" #include "../ld/pe.h" +void dynreloc(void); + /* * divide-and-conquer list-link * sort of Sym* structures. @@ -147,27 +149,49 @@ relocsym(Sym *s) vlong o; uchar *cast; + cursym = s; memset(&p, 0, sizeof p); for(r=s->r; r<s->r+s->nr; r++) { off = r->off; siz = r->siz; + if(off < 0 || off+(siz&~Rbig) > s->np) { + diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz&~Rbig, 0, s->np); + continue; + } + if(r->sym != S && (r->sym->type == 0 || r->sym->type == SXREF)) { + diag("%s: not defined", r->sym->name); + continue; + } + if(r->type >= 256) + continue; + + if(r->sym != S && (r->sym->type == SDYNIMPORT || r->sym->dynimpname != nil)) + diag("unhandled relocation for %s (rtype %d)", r->sym->name, r->type); + + if(r->sym != S && !r->sym->reachable) + diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); + switch(r->type) { default: - diag("unknown reloc %d", r->type); + o = 0; + if(archreloc(r, s, &o) < 0) + diag("unknown reloc %d", r->type); + break; case D_ADDR: - o = symaddr(r->sym); + o = symaddr(r->sym) + r->add; break; case D_PCREL: - o = symaddr(r->sym) - (s->value + r->off + r->siz); + o = symaddr(r->sym) + r->add - (s->value + r->off + r->siz); break; case D_SIZE: - o = r->sym->size; + o = r->sym->size + r->add; break; } - o += r->add; +//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o); switch(siz) { default: - diag("bad reloc size %#ux", siz); + cursym = s; + diag("bad reloc size %#ux for %s", siz, r->sym->name); case 4 + Rbig: fl = o; s->p[off] = fl>>24; @@ -213,6 +237,33 @@ reloc(void) } void +dynrelocsym(Sym *s) +{ + Reloc *r; + + for(r=s->r; r<s->r+s->nr; r++) + if(r->sym->type == SDYNIMPORT || r->type >= 256) + adddynrel(s, r); +} + +void +dynreloc(void) +{ + Sym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f reloc\n", cputime()); + Bflush(&bso); + + for(s=textp; s!=S; s=s->next) + dynrelocsym(s); + for(s=datap; s!=S; s=s->next) + dynrelocsym(s); + if(iself) + elfdynhash(); +} + +void symgrow(Sym *s, int32 siz) { if(s->np >= siz) @@ -240,7 +291,7 @@ savedata(Sym *s, Prog *p) uchar *cast; vlong o; Reloc *r; - + off = p->from.offset; siz = p->datasize; symgrow(s, off+siz); @@ -324,11 +375,13 @@ blk(Sym *allsym, int32 addr, int32 size) uchar *p, *ep; for(sym = allsym; sym != nil; sym = sym->next) - if(sym->value >= addr) + if(!(sym->type&SSUB) && sym->value >= addr) break; eaddr = addr+size; for(; sym != nil; sym = sym->next) { + if(sym->type&SSUB) + continue; if(sym->value >= eaddr) break; if(sym->value < addr) { @@ -411,7 +464,7 @@ codeblk(int32 addr, int32 size) continue; } - Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)addr, sym->name, p); + Bprint(&bso, "%.6llux\t%-20s | %P\n", sym->value, sym->name, p); for(p = p->link; p != P; p = p->link) { if(p->link != P) epc = p->link->pc; @@ -522,6 +575,7 @@ adduintxx(Sym *s, uint64 v, int wid) r = s->size; s->size += wid; symgrow(s, s->size); + assert(r+wid <= s->size); fl = v; cast = (uchar*)&fl; switch(wid) { @@ -571,7 +625,7 @@ adduint64(Sym *s, uint64 v) } vlong -addaddr(Sym *s, Sym *t) +addaddrplus(Sym *s, Sym *t, int32 add) { vlong i; Reloc *r; @@ -587,10 +641,38 @@ addaddr(Sym *s, Sym *t) r->off = i; r->siz = PtrSize; r->type = D_ADDR; + r->add = add; + return i; +} + +vlong +addpcrelplus(Sym *s, Sym *t, int32 add) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += 4; + symgrow(s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->add = add; + r->type = D_PCREL; + r->siz = 4; return i; } vlong +addaddr(Sym *s, Sym *t) +{ + return addaddrplus(s, t, 0); +} + +vlong addsize(Sym *s, Sym *t) { vlong i; @@ -615,7 +697,7 @@ dodata(void) { int32 h, t, datsize; Section *sect; - Sym *s, *last; + Sym *s, *last, **l; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); @@ -645,6 +727,24 @@ dodata(void) diag("%s: initialize bounds (%lld < %d)", s->name, s->size, s->np); } + + /* + * now that we have the datap list, but before we start + * to assign addresses, record all the necessary + * dynamic relocations. these will grow the relocation + * symbol, which is itself data. + */ + dynreloc(); + + /* some symbols may no longer belong in datap (Mach-O) */ + for(l=&datap; (s=*l) != nil; ) { + if(s->type <= STEXT || SXREF <= s->type) + *l = s->next; + else + l = &s->next; + } + *l = nil; + datap = datsort(datap); /* @@ -714,6 +814,40 @@ dodata(void) sect->len = datsize - sect->vaddr; } +// assign addresses to text +void +textaddress(void) +{ + uvlong va; + Prog *p; + Section *sect; + Sym *sym, *sub; + + addsection(&segtext, ".text", 05); + + // Assign PCs in text segment. + // Could parallelize, by assigning to text + // and then letting threads copy down, but probably not worth it. + sect = segtext.sect; + va = INITTEXT; + sect->vaddr = va; + for(sym = textp; sym != nil; sym = sym->next) { + if(sym->type & SSUB) + continue; + sym->value = 0; + for(sub = sym; sub != S; sub = sub->sub) { + sub->value += va; + for(p = sub->text; p != P; p = p->link) + p->pc += sub->value; + } + if(sym->size == 0 && sym->sub != S) { + cursym = sym; + } + va += sym->size; + } + sect->len = va - sect->vaddr; +} + // assign addresses void address(void) @@ -723,7 +857,7 @@ address(void) uvlong va; va = INITTEXT; - segtext.rwx = 05; + segtext.rwx = 07; segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index deaf6a2d8d..d5b0b03111 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -164,8 +164,7 @@ newElfPhdr(void) { ElfPhdr *e; - e = malloc(sizeof *e); - memset(e, 0, sizeof *e); + e = mal(sizeof *e); if (hdr.phnum >= NSECT) diag("too many phdrs"); else @@ -189,8 +188,7 @@ newElfShdr(vlong name) { ElfShdr *e; - e = malloc(sizeof *e); - memset(e, 0, sizeof *e); + e = mal(sizeof *e); e->name = name; if (hdr.shnum >= NSECT) { diag("too many shdrs"); @@ -332,17 +330,25 @@ elfinterp(ElfShdr *sh, uint64 startva, char *p) sh->size = n; } +extern int nelfsym; + void -elfdynhash(int nsym) +elfdynhash(void) { Sym *s, *sy; int i, h, nbucket, b; uchar *pc; uint32 hc, g; uint32 *chain, *buckets; + int nsym; + char *name; + + if(!iself) + return; + nsym = nelfsym; s = lookup(".hash", 0); - s->type = SELFDATA; // TODO: rodata + s->type = SELFDATA; s->reachable = 1; i = nsym; @@ -353,17 +359,24 @@ elfdynhash(int nsym) } chain = malloc(nsym * sizeof(uint32)); - memset(chain, 0, nsym * sizeof(uint32)); buckets = malloc(nbucket * sizeof(uint32)); + if(chain == nil || buckets == nil) { + cursym = nil; + diag("out of memory"); + errorexit(); + } + memset(chain, 0, nsym * sizeof(uint32)); memset(buckets, 0, nbucket * sizeof(uint32)); - i = 1; for(h = 0; h<NHASH; h++) { for(sy=hash[h]; sy!=S; sy=sy->hash) { - if (!sy->reachable || (sy->type != STEXT && sy->type != SDATA && sy->type != SBSS) || sy->dynimpname == nil) + if (sy->dynid <= 0) continue; hc = 0; - for(pc = (uchar*)sy->dynimpname; *pc; pc++) { + name = sy->dynimpname; + if(name == nil) + name = sy->name; + for(pc = (uchar*)name; *pc; pc++) { hc = (hc<<4) + *pc; g = hc & 0xf0000000; hc ^= g >> 24; @@ -371,9 +384,8 @@ elfdynhash(int nsym) } b = hc % nbucket; - chain[i] = buckets[b]; - buckets[b] = i; - i++; + chain[sy->dynid] = buckets[b]; + buckets[b] = sy->dynid; } } @@ -386,6 +398,8 @@ elfdynhash(int nsym) free(chain); free(buckets); + + elfwritedynent(lookup(".dynamic", 0), DT_NULL, 0); } ElfPhdr* diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index aecbe8612a..607cc3f3ad 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -266,6 +266,10 @@ expandpkg(char *t0, char *pkg) // use malloc, not mal, so that caller can free w0 = malloc(strlen(t0) + strlen(pkg)*n); + if(w0 == nil) { + diag("out of memory"); + errorexit(); + } w = w0; for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) { memmove(w, t, p - t); @@ -442,12 +446,21 @@ loaddynimport(char *file, char *pkg, char *p, int n) // successful parse: now can edit the line *strchr(name, ' ') = 0; *strchr(def, ' ') = 0; + + if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) { + // allow #pragma dynimport _ _ "foo.so" + // to force a link of foo.so. + adddynlib(lib); + continue; + } name = expandpkg(name, pkg); - s = lookup(name, 0); - s->dynimplib = lib; - s->dynimpname = def; + if(s->type == 0 || s->type == SXREF) { + s->dynimplib = lib; + s->dynimpname = def; + s->type = SDYNIMPORT; + } } return; @@ -547,6 +560,10 @@ mark(Sym *s) mark(s->r[i].sym); if(s->gotype) mark(s->gotype); + if(s->sub) + mark(s->sub); + if(s->outer) + mark(s->outer); } static char* diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index e666515c04..0aefb3e92b 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -374,32 +374,38 @@ out: void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) { - static int files; - static char **filen; - char **nfilen, *line; - int i, n, c1, c2, c3; + char *line; + int n, c1, c2, c3, c4; + uint32 magic; vlong import0, import1, eof; char src[1024]; eof = Boffset(f) + len; src[0] = '\0'; - // don't load individual object more than once. - // happens with import of .6 files because of loop in xresolv. - // doesn't happen with .a because SYMDEF is consulted - // first to decide whether each individual object file is needed. - for(i=0; i<files; i++) - if(strcmp(filen[i], pn) == 0) - return; + pn = strdup(pn); + + USED(c4); + USED(magic); - if((files&15) == 0){ - nfilen = malloc((files+16)*sizeof(char*)); - memmove(nfilen, filen, files*sizeof(char*)); - free(filen); - filen = nfilen; + c1 = Bgetc(f); + c2 = Bgetc(f); + c3 = Bgetc(f); + c4 = Bgetc(f); + Bungetc(f); + Bungetc(f); + Bungetc(f); + Bungetc(f); + + magic = c1<<24 | c2<<16 | c3<<8 | c4; + if(magic == 0x7f454c46) { // \x7F E L F + ldelf(f, pkg, len, pn); + return; + } + if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) { + ldmacho(f, pkg, len, pn); + return; } - pn = strdup(pn); - filen[files++] = pn; /* check the header */ line = Brdline(f, '\n'); @@ -471,6 +477,9 @@ lookup(char *symb, int v) if(debug['v'] > 1) Bprint(&bso, "lookup %s\n", symb); + s->dynid = -1; + s->plt = -1; + s->got = -1; s->name = mal(l + 1); memmove(s->name, symb, l); @@ -766,11 +775,19 @@ mal(uint32 n) n = (n+7)&~7; if(n > NHUNK) { v = malloc(n); + if(v == nil) { + diag("out of memory"); + errorexit(); + } memset(v, 0, n); return v; } if(n > nhunk) { hunk = malloc(NHUNK); + if(hunk == nil) { + diag("out of memory"); + errorexit(); + } nhunk = NHUNK; } @@ -1013,3 +1030,42 @@ mkfwd(void) } } } + +uint16 +le16(uchar *b) +{ + return b[0] | b[1]<<8; +} + +uint32 +le32(uchar *b) +{ + return b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; +} + +uint64 +le64(uchar *b) +{ + return le32(b) | (uint64)le32(b+4)<<32; +} + +uint16 +be16(uchar *b) +{ + return b[0]<<8 | b[1]; +} + +uint32 +be32(uchar *b) +{ + return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3]; +} + +uint64 +be64(uchar *b) +{ + return (uvlong)be32(b)<<32 | be32(b+4); +} + +Endian be = { be16, be32, be64 }; +Endian le = { le16, le32, le64 }; diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 57a565e808..f11cb34f66 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -125,8 +125,11 @@ void pclntab(void); void symtab(void); void Lflag(char *arg); void usage(void); +void adddynrel(Sym*, Reloc*); void ldobj1(Biobuf *f, char*, int64 len, char *pn); void ldobj(Biobuf*, char*, int64, char*, int); +void ldelf(Biobuf*, char*, int64, char*); +void ldmacho(Biobuf*, char*, int64, char*); void ldpkg(Biobuf*, char*, int64, char*, int); void mark(Sym *s); void mkfwd(void); @@ -144,6 +147,8 @@ vlong addstring(Sym*, char*); vlong adduint32(Sym*, uint32); vlong adduint64(Sym*, uint64); vlong addaddr(Sym*, Sym*); +vlong addaddrplus(Sym*, Sym*, int32); +vlong addpcrelplus(Sym*, Sym*, int32); vlong addsize(Sym*, Sym*); vlong adduint8(Sym*, uint8); vlong adduint16(Sym*, uint16); @@ -152,13 +157,34 @@ void asmelfsym64(void); void strnput(char*, int); void dodata(void); void address(void); +void textaddress(void); void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)); vlong datoff(vlong); +void adddynlib(char*); +int archreloc(Reloc*, Sym*, vlong*); int pathchar(void); void* mal(uint32); void unmal(void*, uint32); void mywhatsys(void); +int rbyoff(const void*, const void*); + +uint16 le16(uchar*); +uint32 le32(uchar*); +uint64 le64(uchar*); +uint16 be16(uchar*); +uint32 be32(uchar*); +uint64 be64(uchar*); + +typedef struct Endian Endian; +struct Endian +{ + uint16 (*e16)(uchar*); + uint32 (*e32)(uchar*); + uint64 (*e64)(uchar*); +}; + +extern Endian be, le; // relocation size bits enum { diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index 67264233c7..45bdd4cefc 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -102,21 +102,12 @@ newMachoDebug(void) // Generic linking code. -static uchar *linkdata; -static uint32 nlinkdata; -static uint32 mlinkdata; - -static uchar *strtab; -static uint32 nstrtab; -static uint32 mstrtab; - struct Expsym { int off; Sym* s; } *expsym; static int nexpsym; -static int nimpsym; static char **dylib; static int ndylib; @@ -199,8 +190,8 @@ machowrite(void) LPUT(t->reloc); LPUT(t->nreloc); LPUT(t->flag); - LPUT(0); /* reserved */ - LPUT(0); /* reserved */ + LPUT(t->res1); /* reserved */ + LPUT(t->res2); /* reserved */ LPUT(0); /* reserved */ } else { strnput(t->name, 16); @@ -212,8 +203,8 @@ machowrite(void) LPUT(t->reloc); LPUT(t->nreloc); LPUT(t->flag); - LPUT(0); /* reserved */ - LPUT(0); /* reserved */ + LPUT(t->res1); /* reserved */ + LPUT(t->res2); /* reserved */ } } } @@ -237,218 +228,53 @@ machowrite(void) return cpos() - 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, ptrsize, t; - char *p; - uchar *dat; - uint32 x; - Sym *s, *smacho; - Sym **impsym; + Sym *s; - ptrsize = 4; - if(macho64) - ptrsize = 8; + if(debug['d']) + return; // empirically, string table must begin with " \x00". - if(!debug['d']) - *(char*)grow(&strtab, &nstrtab, &mstrtab, 2) = ' '; - - impsym = nil; - for(h=0; h<NHASH; h++) { - for(s=hash[h]; s!=S; s=s->hash) { - if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil) - continue; - if(debug['d']) { - diag("cannot use dynamic loading and -d"); - errorexit(); - } - if(!s->dynexport) { - if(nimpsym%32 == 0) { - impsym = realloc(impsym, (nimpsym+32)*sizeof impsym[0]); - if(impsym == nil) { - diag("out of memory"); - errorexit(); - } - } - impsym[nimpsym++] = s; - continue; - } - - /* symbol table entry - darwin still puts _ prefixes on all C symbols */ - x = nstrtab; - p = grow(&strtab, &nstrtab, &mstrtab, 1+strlen(s->dynimpname)+1); - *p++ = '_'; - strcpy(p, s->dynimpname); - - dat = grow(&linkdata, &nlinkdata, &mlinkdata, 8+ptrsize); - dat[0] = x; - dat[1] = x>>8; - dat[2] = x>>16; - dat[3] = x>>24; - - dat[4] = 0x0f; // type: N_SECT | N_EXT - external, defined in sect - switch(s->type) { - default: - case STEXT: - t = 1; - break; - case SDATA: - t = 2; - break; - case SBSS: - t = 4; - break; - } - dat[5] = t; // sect: section number - - if (nexpsym%32 == 0) { - expsym = realloc(expsym, (nexpsym+32)*sizeof expsym[0]); - if (expsym == nil) { - diag("out of memory"); - errorexit(); - } - } - expsym[nexpsym].off = nlinkdata - ptrsize; - expsym[nexpsym++].s = s; - } - } - - smacho = lookup("__nl_symbol_ptr", 0); - smacho->type = SMACHO; - smacho->reachable = 1; - for(h=0; h<nimpsym; h++) { - s = impsym[h]; - s->type = SMACHO | SSUB; - s->sub = smacho->sub; - smacho->sub = s; - s->value = (nexpsym+h) * ptrsize; - s->reachable = 1; - - /* symbol table entry - darwin still puts _ prefixes on all C symbols */ - x = nstrtab; - p = grow(&strtab, &nstrtab, &mstrtab, 1+strlen(s->dynimpname)+1); - *p++ = '_'; - strcpy(p, s->dynimpname); - - 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->dynimplib)) { - if(ndylib%32 == 0) { - dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]); - if(dylib == nil) { - diag("out of memory"); - errorexit(); - } - } - dylib[ndylib++] = s->dynimplib; - } - } - free(impsym); - - /* - * 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<nexpsym+nimpsym; x++) { - dat = grow(&linkdata, &nlinkdata, &mlinkdata, 4); - dat[0] = x; - dat[1] = x>>8; - dat[2] = x>>16; - dat[3] = x>>24; - } - - smacho->size = (nexpsym+nimpsym) * ptrsize; - if(smacho->size == 0) - smacho->reachable = 0; + s = lookup(".dynstr", 0); + s->type = SMACHODYNSTR; + s->reachable = 1; + adduint8(s, ' '); + adduint8(s, '\0'); + + s = lookup(".dynsym", 0); + s->type = SMACHODYNSYM; + s->reachable = 1; + + 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(".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; } -vlong -domacholink(void) +void +machoadddynlib(char *lib) { - int i; - uchar *p; - Sym *s; - uint64 val; - Sym *smacho; - - smacho = lookup("__nl_symbol_ptr", 0); - - linkoff = 0; - if(nlinkdata > 0 || nstrtab > 0) { - linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen - smacho->size, INITRND); - seek(cout, linkoff, 0); - - for(i = 0; i<nexpsym; ++i) { - s = expsym[i].s; - val = s->value; - if(s->type == SXREF) - diag("export of undefined symbol %s", s->name); - if (s->type != STEXT) - val += segdata.vaddr; - p = linkdata+expsym[i].off; - p[0] = val; - p[1] = val >> 8; - p[2] = val >> 16; - p[3] = val >> 24; - if (macho64) { - p[4] = val >> 32; - p[5] = val >> 40; - p[6] = val >> 48; - p[7] = val >> 56; - } + if(ndylib%32 == 0) { + dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]); + if(dylib == nil) { + diag("out of memory"); + errorexit(); } - - ewrite(cout, linkdata, nlinkdata); - ewrite(cout, strtab, nstrtab); } - return rnd(nlinkdata+nstrtab, INITRND); + dylib[ndylib++] = lib; } void @@ -456,14 +282,14 @@ asmbmacho(void) { vlong v, w; vlong va; - int a, i, ptrsize; + int a, i; char *pkgroot; MachoHdr *mh; MachoSect *msect; MachoSeg *ms; MachoDebug *md; MachoLoad *ml; - Sym *smacho; + Sym *s; /* apple MACH */ va = INITTEXT - HEADR; @@ -475,12 +301,10 @@ asmbmacho(void) 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; } @@ -490,7 +314,7 @@ asmbmacho(void) /* text */ v = rnd(HEADR+segtext.len, INITRND); - ms = newMachoSeg("__TEXT", 1); + ms = newMachoSeg("__TEXT", 2); ms->vaddr = va; ms->vsize = v; ms->filesize = v; @@ -502,11 +326,21 @@ asmbmacho(void) 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 */ + } /* data */ - smacho = lookup("__nl_symbol_ptr", 0); w = segdata.len; - ms = newMachoSeg("__DATA", 2+(smacho->size > 0)); + ms = newMachoSeg("__DATA", 3); ms->vaddr = va+v; ms->vsize = w; ms->fileoffset = v; @@ -516,25 +350,18 @@ asmbmacho(void) msect = newMachoSect(ms, "__data"); msect->addr = va+v; - msect->size = segdata.filelen - smacho->size; + msect->size = symaddr(lookup(".got", 0)) - msect->addr; msect->off = v; - if(smacho->size > 0) { + s = lookup(".got", 0); + if(s->size > 0) { msect = newMachoSect(ms, "__nl_symbol_ptr"); - msect->addr = smacho->value; - msect->size = smacho->size; + msect->addr = symaddr(s); + msect->size = s->size; msect->off = datoff(msect->addr); 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->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ } msect = newMachoSect(ms, "__bss"); @@ -562,39 +389,43 @@ asmbmacho(void) } if(!debug['d']) { - int nsym; + Sym *s1, *s2, *s3, *s4; - nsym = smacho->size/ptrsize; + // must match domacholink below + s1 = lookup(".dynsym", 0); + s2 = lookup(".dynstr", 0); + s3 = lookup(".linkedit.plt", 0); + s4 = lookup(".linkedit.got", 0); ms = newMachoSeg("__LINKEDIT", 0); ms->vaddr = va+v+rnd(segdata.len, INITRND); - ms->vsize = nlinkdata+nstrtab; + ms->vsize = s1->size + s2->size + s3->size + s4->size; ms->fileoffset = linkoff; - ms->filesize = nlinkdata+nstrtab; + ms->filesize = ms->vsize; 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->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */ + ml->data[2] = linkoff + s1->size; /* stroff */ + ml->data[3] = s2->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] = nexpsym; /* nextdefsym */ - ml->data[4] = nexpsym; /* iundefsym */ - ml->data[5] = nimpsym; /* nundefsym */ + ml->data[3] = 0; /* nextdefsym */ // TODO nexpsym + ml->data[4] = 0; /* iundefsym */ // TODO nexpsym + ml->data[5] = s1->size / (macho64 ? 16 : 12); /* 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[12] = linkoff + s1->size + s2->size; /* indirectsymoff */ + ml->data[13] = (s3->size + s4->size) / 4; /* nindirectsyms */ ml->data[14] = 0; /* extreloff */ ml->data[15] = 0; /* nextrel */ ml->data[16] = 0; /* locreloff */ @@ -640,3 +471,33 @@ asmbmacho(void) if(a > MACHORESERVE) diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE); } + +vlong +domacholink(void) +{ + int size; + Sym *s1, *s2, *s3, *s4; + + // write data that will be linkedit section + s1 = lookup(".dynsym", 0); + s2 = lookup(".dynstr", 0); + s3 = lookup(".linkedit.plt", 0); + s4 = lookup(".linkedit.got", 0); + + while(s2->size%4) + adduint8(s2, 0); + + size = s1->size + s2->size + s3->size + s4->size; + + if(size > 0) { + linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND); + seek(cout, linkoff, 0); + + ewrite(cout, s1->p, s1->size); + ewrite(cout, s2->p, s2->size); + ewrite(cout, s3->p, s3->size); + ewrite(cout, s4->p, s4->size); + } + + return rnd(size, INITRND); +} diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h index 524e7ae4e8..03f1d2c321 100644 --- a/src/cmd/ld/macho.h +++ b/src/cmd/ld/macho.h @@ -18,6 +18,8 @@ struct MachoSect { uint32 reloc; uint32 nreloc; uint32 flag; + uint32 res1; + uint32 res2; }; typedef struct MachoSeg MachoSeg; @@ -70,6 +72,20 @@ enum { MACHO32SYMSIZE = 12, MACHO64SYMSIZE = 16, + + MACHO_X86_64_RELOC_UNSIGNED = 0, + MACHO_X86_64_RELOC_SIGNED = 1, + MACHO_X86_64_RELOC_BRANCH = 2, + MACHO_X86_64_RELOC_GOT_LOAD = 3, + MACHO_X86_64_RELOC_GOT = 4, + MACHO_X86_64_RELOC_SUBTRACTOR = 5, + MACHO_X86_64_RELOC_SIGNED_1 = 6, + MACHO_X86_64_RELOC_SIGNED_2 = 7, + MACHO_X86_64_RELOC_SIGNED_4 = 8, + + MACHO_GENERIC_RELOC_VANILLA = 0, + + MACHO_FAKE_GOTPCREL = 100, }; void domacho(void); |
