]> Cypherpunks repositories - gostls13.git/commitdiff
6l, 8l: support for linking ELF and Mach-O .o files
authorRuss Cox <rsc@golang.org>
Wed, 8 Dec 2010 18:56:43 +0000 (13:56 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 8 Dec 2010 18:56:43 +0000 (13:56 -0500)
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

14 files changed:
src/cmd/6l/Makefile
src/cmd/6l/asm.c
src/cmd/6l/l.h
src/cmd/8l/8.out.h
src/cmd/8l/Makefile
src/cmd/8l/asm.c
src/cmd/8l/l.h
src/cmd/ld/data.c
src/cmd/ld/elf.c
src/cmd/ld/go.c
src/cmd/ld/lib.c
src/cmd/ld/lib.h
src/cmd/ld/macho.c
src/cmd/ld/macho.h

index 94e520a93e031cd4e056bab936eedf6821ebbfe6..fba1b42ae4de36d3ffa3d400a270ce4e6c1e6d10 100644 (file)
@@ -14,6 +14,8 @@ OFILES=\
        elf.$O\
        enam.$O\
        go.$O\
+       ldelf.$O\
+       ldmacho.$O\
        lib.$O\
        list.$O\
        macho.$O\
index 83cb4906ac64366984dd153bd751c3476c5de3f2..dca2313d128a69bdc4a734baa68c617a2a97d32a 100644 (file)
@@ -138,6 +138,8 @@ enum {
        ElfStrShstrtab,
        ElfStrSymtab,
        ElfStrStrtab,
+       ElfStrRelaPlt,
+       ElfStrPlt,
        NElfStr
 };
 
@@ -159,11 +161,391 @@ needlib(char *name)
        return 0;
 }
 
+int nelfsym = 1;
+
+static void    adddynsym(Sym*);
+static void addpltsym(Sym*);
+static void addgotsym(Sym*);
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+       Sym *targ, *rela, *got;
+       
+       targ = r->sym;
+       cursym = s;
+
+       switch(r->type) {
+       default:
+               if(r->type >= 256) {
+                       diag("unexpected relocation type %d", r->type);
+                       return;
+               }
+               break;
+
+       // Handle relocations found in ELF object files.
+       case 256 + R_X86_64_PC32:
+               if(targ->dynimpname)
+                       diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
+               if(targ->type == 0 || targ->type == SXREF)
+                       diag("unknown symbol %s in pcrel", targ->name);
+               r->type = D_PCREL;
+               r->add += 4;
+               return;
+       
+       case 256 + R_X86_64_PLT32:
+               addpltsym(targ);
+               r->type = D_PCREL;
+               r->sym = lookup(".plt", 0);
+               r->add += 4;
+               r->add += targ->plt;
+               return;
+       
+       case 256 + R_X86_64_GOTPCREL:
+               addgotsym(targ);
+               r->type = D_PCREL;
+               r->sym = lookup(".got", 0);
+               r->add += 4;
+               r->add += targ->got;
+               return;
+       
+       case 256 + R_X86_64_64:
+               if(targ->dynimpname)
+                       diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
+               r->type = D_ADDR;
+               return;
+       
+       // Handle relocations found in Mach-O object files.
+       case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
+       case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
+       case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
+               // TODO: What is the difference between all these?
+               r->type = D_ADDR;
+               if(targ->dynimpname)
+                       diag("unexpected reloc for dynamic symbol %s", targ->name);
+               return;
+
+       case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
+               if(targ->dynimpname) {
+                       addpltsym(targ);
+                       r->sym = lookup(".plt", 0);
+                       r->add = targ->plt;
+                       r->type = D_PCREL;
+                       return;
+               }
+               // fall through
+       case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
+       case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
+       case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
+       case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
+       case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
+               r->type = D_PCREL;
+               if(targ->dynimpname)
+                       diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
+               return;
+
+       case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
+       case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
+               // TODO: What is the difference between these two?
+               addgotsym(targ);
+               r->type = D_PCREL;
+               r->sym = lookup(".got", 0);
+               r->add += targ->got;
+               return;
+       }
+       
+       // Handle references to ELF symbols from our own object files.
+       if(targ->dynimpname == nil)
+               return;
+
+       switch(r->type) {
+       case D_PCREL:
+               addpltsym(targ);
+               r->sym = lookup(".plt", 0);
+               r->add = targ->plt;
+               return;
+       
+       case D_ADDR:
+               if(s->type != SDATA)
+                       break;
+               if(iself) {
+                       adddynsym(targ);
+                       rela = lookup(".rela", 0);
+                       addaddrplus(rela, s, r->off);
+                       if(r->siz == 8)
+                               adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
+                       else
+                               adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
+                       adduint64(rela, r->add);
+                       r->type = 256;  // ignore during relocsym
+                       return;
+               }
+               if(HEADTYPE == 6 && s->size == PtrSize && r->off == 0) {
+                       // Mach-O relocations are a royal pain to lay out.
+                       // They use a compact stateful bytecode representation
+                       // that is too much bother to deal with.
+                       // Instead, interpret the C declaration
+                       //      void *_Cvar_stderr = &stderr;
+                       // as making _Cvar_stderr the name of a GOT entry
+                       // for stderr.  This is separate from the usual GOT entry,
+                       // just in case the C code assigns to the variable,
+                       // and of course it only works for single pointers,
+                       // but we only need to support cgo and that's all it needs.
+                       adddynsym(targ);
+                       got = lookup(".got", 0);
+                       s->type = got->type | SSUB;
+                       s->outer = got;
+                       s->sub = got->sub;
+                       got->sub = s;
+                       s->value = got->size;
+                       adduint64(got, 0);
+                       adduint32(lookup(".linkedit.got", 0), targ->dynid);
+                       r->type = 256;  // ignore during relocsym
+                       return;
+               }
+               break;
+       }
+       
+       cursym = s;
+       diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+       return -1;
+}
+
+static void
+elfsetupplt(void)
+{
+       Sym *plt, *got;
+
+       plt = lookup(".plt", 0);
+       got = lookup(".got.plt", 0);
+       if(plt->size == 0) {
+               // pushq got+8(IP)
+               adduint8(plt, 0xff);
+               adduint8(plt, 0x35);
+               addpcrelplus(plt, got, 8);
+               
+               // jmpq got+16(IP)
+               adduint8(plt, 0xff);
+               adduint8(plt, 0x25);
+               addpcrelplus(plt, got, 16);
+               
+               // nopl 0(AX)
+               adduint32(plt, 0x00401f0f);
+               
+               // assume got->size == 0 too
+               addaddrplus(got, lookup(".dynamic", 0), 0);
+               adduint64(got, 0);
+               adduint64(got, 0);
+       }
+}
+
+static void
+addpltsym(Sym *s)
+{
+       if(s->plt >= 0)
+               return;
+       
+       adddynsym(s);
+       
+       if(iself) {
+               Sym *plt, *got, *rela;
+
+               plt = lookup(".plt", 0);
+               got = lookup(".got.plt", 0);
+               rela = lookup(".rela.plt", 0);
+               if(plt->size == 0)
+                       elfsetupplt();
+               
+               // jmpq *got+size(IP)
+               adduint8(plt, 0xff);
+               adduint8(plt, 0x25);
+               addpcrelplus(plt, got, got->size);
+       
+               // add to got: pointer to current pos in plt
+               addaddrplus(got, plt, plt->size);
+               
+               // pushq $x
+               adduint8(plt, 0x68);
+               adduint32(plt, (got->size-24-8)/8);
+               
+               // jmpq .plt
+               adduint8(plt, 0xe9);
+               adduint32(plt, -(plt->size+4));
+               
+               // rela
+               addaddrplus(rela, got, got->size-8);
+               adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
+               adduint64(rela, 0);
+               
+               s->plt = plt->size - 16;
+       } else if(HEADTYPE == 6) {      // Mach-O
+               // To do lazy symbol lookup right, we're supposed
+               // to tell the dynamic loader which library each 
+               // symbol comes from and format the link info
+               // section just so.  I'm too lazy (ha!) to do that
+               // so for now we'll just use non-lazy pointers,
+               // which don't need to be told which library to use.
+               //
+               // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
+               // has details about what we're avoiding.
+
+               Sym *plt;
+               
+               addgotsym(s);
+               plt = lookup(".plt", 0);
+
+               adduint32(lookup(".linkedit.plt", 0), s->dynid);
+
+               // jmpq *got+size(IP)
+               s->plt = plt->size;
+
+               adduint8(plt, 0xff);
+               adduint8(plt, 0x25);
+               addpcrelplus(plt, lookup(".got", 0), s->got);
+       } else {
+               diag("addpltsym: unsupported binary format");
+       }
+}
+
+static void
+addgotsym(Sym *s)
+{
+       Sym *got, *rela, *indir;
+
+       if(s->got >= 0)
+               return;
+
+       adddynsym(s);
+       got = lookup(".got", 0);
+       s->got = got->size;
+       adduint64(got, 0);
+
+       if(iself) {
+               rela = lookup(".rela", 0);
+               addaddrplus(rela, got, s->got);
+               adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
+               adduint64(rela, 0);
+       } else if(HEADTYPE == 6) {      // Mach-O
+               adduint32(lookup(".linkedit.got", 0), s->dynid);
+       } else {
+               diag("addgotsym: unsupported binary format");
+       }
+}
+
+static void
+adddynsym(Sym *s)
+{
+       Sym *d, *str;
+       int t;
+       char *name;
+
+       if(s->dynid >= 0)
+               return;
+
+       if(iself) {
+               s->dynid = nelfsym++;
+       
+               d = lookup(".dynsym", 0);
+               name = s->dynimpname;
+               if(name == nil)
+                       name = s->name;
+               adduint32(d, addstring(lookup(".dynstr", 0), name));
+               /* type */
+               t = STB_GLOBAL << 4;
+               if(s->dynexport && s->type == STEXT)
+                       t |= STT_FUNC;
+               else
+                       t |= STT_OBJECT;
+               adduint8(d, t);
+       
+               /* reserved */
+               adduint8(d, 0);
+       
+               /* section where symbol is defined */
+               if(!s->dynexport && s->dynimpname != nil)
+                       adduint16(d, SHN_UNDEF);
+               else {
+                       switch(s->type) {
+                       default:
+                       case STEXT:
+                               t = 11;
+                               break;
+                       case SRODATA:
+                               t = 12;
+                               break;
+                       case SDATA:
+                               t = 13;
+                               break;
+                       case SBSS:
+                               t = 14;
+                               break;
+                       }
+                       adduint16(d, t);
+               }
+       
+               /* value */
+               if(s->type == SDYNIMPORT)
+                       adduint64(d, 0);
+               else
+                       addaddr(d, s);
+       
+               /* size of object */
+               adduint64(d, 0);
+       
+               if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
+                       elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
+                               addstring(lookup(".dynstr", 0), s->dynimplib));
+               }
+       } else if(HEADTYPE == 6) {
+               // Mach-o symbol nlist64
+               d = lookup(".dynsym", 0);
+               name = s->dynimpname;
+               if(name == nil)
+                       name = s->name;
+               s->dynid = d->size/16;
+               // darwin still puts _ prefixes on all C symbols
+               str = lookup(".dynstr", 0);
+               adduint32(d, str->size);
+               adduint8(str, '_');
+               addstring(str, name);
+               adduint8(d, 0x01);      // type - N_EXT - external symbol
+               adduint8(d, 0); // section
+               adduint16(d, 0);        // desc
+               adduint64(d, 0);        // value
+       } else {
+               diag("adddynsym: unsupported binary format");
+       }
+}
+
+void
+adddynlib(char *lib)
+{
+       Sym *s;
+       
+       if(!needlib(lib))
+               return;
+       
+       if(iself) {
+               s = lookup(".dynstr", 0);
+               if(s->size == 0)
+                       addstring(s, "");
+               elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+       } else if(HEADTYPE == 6) {      // Mach-O
+               machoadddynlib(lib);
+       } else {
+               diag("adddynlib: unsupported binary format");
+       }
+}
+
 void
 doelf(void)
 {
-       Sym *s, *shstrtab, *dynamic, *dynstr, *d;
-       int h, nsym, t;
+       Sym *s, *shstrtab, *dynstr;
 
        if(HEADTYPE != 7 && HEADTYPE != 9)
                return;
@@ -198,6 +580,8 @@ doelf(void)
                elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
                elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
                elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
+               elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
+               elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
 
                /* dynamic symbol table - first entry all zeros */
                s = lookup(".dynsym", 0);
@@ -209,7 +593,8 @@ doelf(void)
                s = lookup(".dynstr", 0);
                s->type = SELFDATA;
                s->reachable = 1;
-               addstring(s, "");
+               if(s->size == 0)
+                       addstring(s, "");
                dynstr = s;
 
                /* relocation table */
@@ -220,15 +605,24 @@ doelf(void)
                /* global offset table */
                s = lookup(".got", 0);
                s->reachable = 1;
+               s->type = SDATA;        // writable, so not SELFDATA
+
+               /* hash */
+               s = lookup(".hash", 0);
+               s->reachable = 1;
                s->type = SELFDATA;
 
-               /* got.plt - ??? */
                s = lookup(".got.plt", 0);
                s->reachable = 1;
+               s->type = SDATA;        // writable, not SELFDATA
+
+               s = lookup(".plt", 0);
+               s->reachable = 1;
                s->type = SELFDATA;
                
-               /* hash */
-               s = lookup(".hash", 0);
+               elfsetupplt();
+               
+               s = lookup(".rela.plt", 0);
                s->reachable = 1;
                s->type = SELFDATA;
 
@@ -236,78 +630,10 @@ doelf(void)
                s = lookup(".dynamic", 0);
                s->reachable = 1;
                s->type = SELFDATA;
-               dynamic = s;
-
-               /*
-                * relocation entries for dynimport symbols
-                */
-               nsym = 1;       // sym 0 is reserved
-               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(!s->dynexport) {
-                                       d = lookup(".rela", 0);
-                                       addaddr(d, s);
-                                       adduint64(d, ELF64_R_INFO(nsym, R_X86_64_64));
-                                       adduint64(d, 0);
-                               }
-
-                               nsym++;
-
-                               d = lookup(".dynsym", 0);
-                               adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
-                               /* type */
-                               t = STB_GLOBAL << 4;
-                               if(s->dynexport && s->type == STEXT)
-                                       t |= STT_FUNC;
-                               else
-                                       t |= STT_OBJECT;
-                               adduint8(d, t);
-
-                               /* reserved */
-                               adduint8(d, 0);
-
-                               /* section where symbol is defined */
-                               if(!s->dynexport)
-                                       adduint16(d, SHN_UNDEF);
-                               else {
-                                       switch(s->type) {
-                                       default:
-                                       case STEXT:
-                                               t = 9;
-                                               break;
-                                       case SDATA:
-                                               t = 10;
-                                               break;
-                                       case SBSS:
-                                               t = 11;
-                                               break;
-                                       }
-                                       adduint16(d, t);
-                               }
-
-                               /* value */
-                               if(!s->dynexport)
-                                       adduint64(d, 0);
-                               else
-                                       addaddr(d, s);
-
-                               /* size of object */
-                               adduint64(d, 0);
-
-                               if(!s->dynexport && needlib(s->dynimplib))
-                                       elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
-                       }
-               }
-
-               elfdynhash(nsym);
 
                /*
                 * .dynamic table
                 */
-               s = dynamic;
                elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
                elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
                elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
@@ -318,6 +644,11 @@ doelf(void)
                elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
                if(rpath)
                        elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+               
+               elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+               elfwritedynent(s, DT_PLTREL, DT_RELA);
+               elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
+               elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
                elfwritedynent(s, DT_NULL, 0);
        }
 }
@@ -398,10 +729,10 @@ asmb(void)
        case 9:
                debug['8'] = 1; /* 64-bit addresses */
                /* index of elf text section; needed by asmelfsym, double-checked below */
-               /* !debug['d'] causes extra sections before the .text section */
+               /* !debug['d'] causes extra sections before the .text section */
                elftextsh = 1;
                if(!debug['d'])
-                       elftextsh += 8;
+                       elftextsh += 10;
                break;
        }
 
@@ -562,7 +893,7 @@ asmb(void)
                        sh->entsize = 8;
                        sh->addralign = 8;
                        shsym(sh, lookup(".got.plt", 0));
-
+                       
                        dynsym = eh->shnum;
                        sh = newElfShdr(elfstr[ElfStrDynsym]);
                        sh->type = SHT_DYNSYM;
@@ -579,6 +910,22 @@ asmb(void)
                        sh->addralign = 1;
                        shsym(sh, lookup(".dynstr", 0));
 
+                       sh = newElfShdr(elfstr[ElfStrRelaPlt]);
+                       sh->type = SHT_RELA;
+                       sh->flags = SHF_ALLOC;
+                       sh->entsize = ELF64RELASIZE;
+                       sh->addralign = 8;
+                       sh->link = dynsym;
+                       sh->info = eh->shnum;   // .plt
+                       shsym(sh, lookup(".rela.plt", 0));
+
+                       sh = newElfShdr(elfstr[ElfStrPlt]);
+                       sh->type = SHT_PROGBITS;
+                       sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+                       sh->entsize = 16;
+                       sh->addralign = 4;
+                       shsym(sh, lookup(".plt", 0));
+
                        sh = newElfShdr(elfstr[ElfStrHash]);
                        sh->type = SHT_HASH;
                        sh->flags = SHF_ALLOC;
@@ -744,12 +1091,12 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
 
        for(h=0; h<NHASH; h++) {
                for(s=hash[h]; s!=S; s=s->hash) {
-                       switch(s->type) {
+                       switch(s->type&~SSUB) {
                        case SCONST:
                        case SRODATA:
                        case SDATA:
                        case SELFDATA:
-                       case SMACHO:
+                       case SMACHOGOT:
                                if(!s->reachable)
                                        continue;
                                put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
@@ -769,6 +1116,9 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
        }
 
        for(s = textp; s != nil; s = s->next) {
+               if(s->text == nil)
+                       continue;
+
                /* filenames first */
                for(a=s->autom; a; a=a->link)
                        if(a->type == D_FILE)
@@ -777,7 +1127,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
                        if(a->type == D_FILE1)
                                put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
 
-               put(s, s->name, 'T', 0, s->size, s->version, s->gotype);
+               put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
 
                /* frame, auto and param after */
                put(nil, ".frame", 'm', s->text->to.offset+8, 0, 0, 0);
index 39b3866d2d99e53e31c1fda535ec5721b7fe4b72..9260304b404ad790ce3186fbf4dbf1156603d2b0 100644 (file)
@@ -84,7 +84,7 @@ struct        Reloc
 {
        int32   off;
        uchar   siz;
-       uchar   type;
+       int32   type;
        int64   add;
        Sym*    sym;
 };
@@ -128,10 +128,14 @@ struct    Sym
        uchar   reachable;
        uchar   dynexport;
        uchar   special;
+       int32   dynid;
        int32   sig;
+       int32   plt;
+       int32   got;
        Sym*    hash;   // in hash table
        Sym*    next;   // in text or data list
        Sym*    sub;    // in SSUB list
+       Sym*    outer;  // container of sub
        vlong   value;
        vlong   size;
        Sym*    gotype;
@@ -174,14 +178,20 @@ enum
        /* order here is order in output file */
        STEXT           = 1,
        SELFDATA,
+       SMACHOPLT,
        SRODATA,
        SDATA,
-       SMACHO,
+       SMACHOGOT,
        SBSS,
 
        SXREF,
+       SMACHODYNSTR,
+       SMACHODYNSYM,
+       SMACHOINDIRECTPLT,
+       SMACHOINDIRECTGOT,
        SFILE,
        SCONST,
+       SDYNIMPORT,
        SSUB    = 1<<8,
 
        NHASH           = 10007,
index 4057fb27aeb232e61d36192919271a615fa27199..c41a676d438dcf5986bc324ca0682d14c6d93240 100644 (file)
@@ -500,6 +500,8 @@ enum
        D_CONST2 = D_INDIR+D_INDIR,
        D_SIZE, /* 8l internal */
        D_PCREL,
+       D_GOTOFF,
+       D_GOTPCREL,
 
        T_TYPE          = 1<<0,
        T_INDEX         = 1<<1,
index f814ab3993826c748bbab30786f389f9659a38c9..84976ba18b49d68bd74f9cc9f69abe8174cb47bf 100644 (file)
@@ -14,6 +14,8 @@ OFILES=\
        elf.$O\
        enam.$O\
        go.$O\
+       ldelf.$O\
+       ldmacho.$O\
        lib.$O\
        list.$O\
        macho.$O\
index 956a2fe6e45f895f4f6e84f67e0a53a2c15c233f..85e6f39362e6dcca938026835a49b9ea8ad52369 100644 (file)
@@ -126,6 +126,10 @@ enum {
        ElfStrGosymtab,
        ElfStrGopclntab,
        ElfStrShstrtab,
+       ElfStrSymtab,
+       ElfStrStrtab,
+       ElfStrRelPlt,
+       ElfStrPlt,
        NElfStr
 };
 
@@ -147,11 +151,380 @@ needlib(char *name)
        return 0;
 }
 
+int    nelfsym = 1;
+
+static void    adddynsym(Sym*);
+static void    addpltsym(Sym*);
+static void    addgotsym(Sym*);
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+       Sym *targ, *rel, *got;
+
+       targ = r->sym;
+       cursym = s;
+
+       switch(r->type) {
+       default:
+               if(r->type >= 256) {
+                       diag("unexpected relocation type %d", r->type);
+                       return;
+               }
+               break;
+
+       // Handle relocations found in ELF object files.
+       case 256 + R_386_PC32:
+               if(targ->dynimpname)
+                       diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
+               if(targ->type == 0 || targ->type == SXREF)
+                       diag("unknown symbol %s in pcrel", targ->name);
+               r->type = D_PCREL;
+               r->add += 4;
+               return;
+
+       case 256 + R_386_PLT32:
+               addpltsym(targ);
+               r->type = D_PCREL;
+               r->sym = lookup(".plt", 0);
+               r->add += 4;
+               r->add += targ->plt;
+               return;         
+       
+       case 256 + R_386_GOT32:
+               addgotsym(targ);
+               r->type = D_CONST;      // write r->add during relocsym
+               r->sym = S;
+               r->add += targ->got;
+               return;
+       
+       case 256 + R_386_GOTOFF:
+               r->type = D_GOTOFF;
+               return;
+       
+       case 256 + R_386_GOTPC:
+               r->type = D_PCREL;
+               r->sym = lookup(".got", 0);
+               r->add += 4;
+               return;
+
+       case 256 + R_386_32:
+               if(targ->dynimpname)
+                       diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
+               r->type = D_ADDR;
+               return;
+       
+       case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
+               r->type = D_ADDR;
+               if(targ->dynimpname)
+                       diag("unexpected reloc for dynamic symbol %s", targ->name);
+               return;
+       
+       case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
+               if(targ->dynimpname) {
+                       addpltsym(targ);
+                       r->sym = lookup(".plt", 0);
+                       r->add = targ->plt;
+                       r->type = D_PCREL;
+                       return;
+               }
+               r->type = D_PCREL;
+               if(targ->dynimpname)
+                       diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
+               return;
+       
+       case 512 + MACHO_FAKE_GOTPCREL:
+               addgotsym(targ);
+               r->sym = lookup(".got", 0);
+               r->add += targ->got;
+               r->type = D_PCREL;
+               return;
+       }
+       
+       // Handle references to ELF symbols from our own object files.
+       if(targ->dynimpname == nil)
+               return;
+
+       switch(r->type) {
+       case D_PCREL:
+               addpltsym(targ);
+               r->sym = lookup(".plt", 0);
+               r->add = targ->plt;
+               return;
+       
+       case D_ADDR:
+               if(s->type != SDATA)
+                       break;
+               if(iself) {
+                       adddynsym(targ);
+                       rel = lookup(".rel", 0);
+                       addaddrplus(rel, s, r->off);
+                       adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
+                       r->type = D_CONST;      // write r->add during relocsym
+                       r->sym = S;
+                       return;
+               }
+               if(HEADTYPE == 6 && s->size == PtrSize && r->off == 0) {
+                       // Mach-O relocations are a royal pain to lay out.
+                       // They use a compact stateful bytecode representation
+                       // that is too much bother to deal with.
+                       // Instead, interpret the C declaration
+                       //      void *_Cvar_stderr = &stderr;
+                       // as making _Cvar_stderr the name of a GOT entry
+                       // for stderr.  This is separate from the usual GOT entry,
+                       // just in case the C code assigns to the variable,
+                       // and of course it only works for single pointers,
+                       // but we only need to support cgo and that's all it needs.
+                       adddynsym(targ);
+                       got = lookup(".got", 0);
+                       s->type = got->type | SSUB;
+                       s->outer = got;
+                       s->sub = got->sub;
+                       got->sub = s;
+                       s->value = got->size;
+                       adduint32(got, 0);
+                       adduint32(lookup(".linkedit.got", 0), targ->dynid);
+                       r->type = 256;  // ignore during relocsym
+                       return;
+               }
+               break;
+       }
+       
+       cursym = s;
+       diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+static void
+elfsetupplt(void)
+{
+       Sym *plt, *got;
+       
+       plt = lookup(".plt", 0);
+       got = lookup(".got.plt", 0);
+       if(plt->size == 0) {
+               // pushl got+4
+               adduint8(plt, 0xff);
+               adduint8(plt, 0x35);
+               addaddrplus(plt, got, 4);
+               
+               // jmp *got+8
+               adduint8(plt, 0xff);
+               adduint8(plt, 0x25);
+               addaddrplus(plt, got, 8);
+
+               // zero pad
+               adduint32(plt, 0);
+               
+               // assume got->size == 0 too
+               addaddrplus(got, lookup(".dynamic", 0), 0);
+               adduint32(got, 0);
+               adduint32(got, 0);
+       }
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+       switch(r->type) {
+       case D_CONST:
+               *val = r->add;
+               return 0;
+       case D_GOTOFF:
+               *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+               return 0;
+       }
+       return -1;
+}
+
+static void
+addpltsym(Sym *s)
+{
+       Sym *plt, *got, *rel;
+       
+       if(s->plt >= 0)
+               return;
+
+       adddynsym(s);
+       
+       if(iself) {
+               plt = lookup(".plt", 0);
+               got = lookup(".got.plt", 0);
+               rel = lookup(".rel.plt", 0);
+               if(plt->size == 0)
+                       elfsetupplt();
+               
+               // jmpq *got+size
+               adduint8(plt, 0xff);
+               adduint8(plt, 0x25);
+               addaddrplus(plt, got, got->size);
+               
+               // add to got: pointer to current pos in plt
+               addaddrplus(got, plt, plt->size);
+               
+               // pushl $x
+               adduint8(plt, 0x68);
+               adduint32(plt, rel->size);
+               
+               // jmp .plt
+               adduint8(plt, 0xe9);
+               adduint32(plt, -(plt->size+4));
+               
+               // rel
+               addaddrplus(rel, got, got->size-4);
+               adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
+               
+               s->plt = plt->size - 16;
+       } else if(HEADTYPE == 6) {      // Mach-O
+               // Same laziness as in 6l.
+               
+               Sym *plt;
+
+               plt = lookup(".plt", 0);
+
+               addgotsym(s);
+
+               adduint32(lookup(".linkedit.plt", 0), s->dynid);
+
+               // jmpq *got+size(IP)
+               s->plt = plt->size;
+
+               adduint8(plt, 0xff);
+               adduint8(plt, 0x25);
+               addaddrplus(plt, lookup(".got", 0), s->got);
+       } else {
+               diag("addpltsym: unsupported binary format");
+       }
+}
+
+static void
+addgotsym(Sym *s)
+{
+       Sym *got, *rel;
+       
+       if(s->got >= 0)
+               return;
+       
+       adddynsym(s);
+       got = lookup(".got", 0);
+       s->got = got->size;
+       adduint32(got, 0);
+       
+       if(iself) {
+               rel = lookup(".rel", 0);
+               addaddrplus(rel, got, s->got);
+               adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
+       } else if(HEADTYPE == 6) {      // Mach-O
+               adduint32(lookup(".linkedit.got", 0), s->dynid);
+       } else {
+               diag("addgotsym: unsupported binary format");
+       }
+}
+
+static void
+adddynsym(Sym *s)
+{
+       Sym *d, *str;
+       int t;
+       char *name;
+       
+       if(s->dynid >= 0)
+               return;
+       
+       if(iself) {
+               s->dynid = nelfsym++;
+               
+               d = lookup(".dynsym", 0);
+               
+               /* name */
+               name = s->dynimpname;
+               if(name == nil)
+                       name = s->name;
+               adduint32(d, addstring(lookup(".dynstr", 0), name));
+               
+               /* value */
+               if(s->type == SDYNIMPORT)
+                       adduint32(d, 0);
+               else
+                       addaddr(d, s);
+               
+               /* size */
+               adduint32(d, 0);
+       
+               /* type */
+               t = STB_GLOBAL << 4;
+               if(s->dynexport && s->type == STEXT)
+                       t |= STT_FUNC;
+               else
+                       t |= STT_OBJECT;
+               adduint8(d, t);
+               adduint8(d, 0);
+       
+               /* shndx */
+               if(!s->dynexport && s->dynimpname != nil)
+                       adduint16(d, SHN_UNDEF);
+               else {
+                       switch(s->type) {
+                       default:
+                       case STEXT:
+                               t = 11;
+                               break;
+                       case SRODATA:
+                               t = 12;
+                               break;
+                       case SDATA:
+                               t = 13;
+                               break;
+                       case SBSS:
+                               t = 14;
+                               break;
+                       }
+                       adduint16(d, t);
+               }
+       } else if(HEADTYPE == 6) {
+               // Mach-O symbol nlist32
+               d = lookup(".dynsym", 0);
+               name = s->dynimpname;
+               if(name == nil)
+                       name = s->name;
+               s->dynid = d->size/12;
+               // darwin still puts _ prefixes on all C symbols
+               str = lookup(".dynstr", 0);
+               adduint32(d, str->size);
+               adduint8(str, '_');
+               addstring(str, name);
+               adduint8(d, 0x01);      // type - N_EXT - external symbol
+               adduint8(d, 0); // section
+               adduint16(d, 0);        // desc
+               adduint32(d, 0);        // value
+       } else {
+               diag("adddynsym: unsupported binary format");
+       }
+}
+
+void
+adddynlib(char *lib)
+{
+       Sym *s;
+       
+       if(!needlib(lib))
+               return;
+       
+       if(iself) {
+               s = lookup(".dynstr", 0);
+               if(s->size == 0)
+                       addstring(s, "");
+               elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+       } else if(HEADTYPE == 6) {      // Mach-O
+               machoadddynlib(lib);
+       } else {
+               diag("adddynlib: unsupported binary format");
+       }
+}
+
 void
 doelf(void)
 {
-       Sym *s, *shstrtab, *dynamic, *dynstr, *d;
-       int h, nsym, t;
+       Sym *s, *shstrtab, *dynstr;
 
        if(!iself)
                return;
@@ -186,6 +559,8 @@ doelf(void)
                elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
                elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
                elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
+               elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
+               elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
 
                /* interpreter string */
                s = lookup(".interp", 0);
@@ -202,7 +577,8 @@ doelf(void)
                s = lookup(".dynstr", 0);
                s->reachable = 1;
                s->type = SELFDATA;
-               addstring(s, "");
+               if(s->size == 0)
+                       addstring(s, "");
                dynstr = s;
 
                /* relocation table */
@@ -213,88 +589,36 @@ doelf(void)
                /* global offset table */
                s = lookup(".got", 0);
                s->reachable = 1;
+               s->type = SDATA;        // writable, so not SELFDATA
+               
+               /* hash */
+               s = lookup(".hash", 0);
+               s->reachable = 1;
                s->type = SELFDATA;
 
-               /* got.plt - ??? */
+               /* got.plt */
                s = lookup(".got.plt", 0);
                s->reachable = 1;
+               s->type = SDATA;        // writable, so not SELFDATA
+               
+               s = lookup(".plt", 0);
+               s->reachable = 1;
                s->type = SELFDATA;
 
-               /* define dynamic elf table */
-               s = lookup(".dynamic", 0);
+               s = lookup(".rel.plt", 0);
                s->reachable = 1;
                s->type = SELFDATA;
-               dynamic = s;
 
-               /*
-                * relocation entries for dynimport symbols
-                */
-               nsym = 1;       // sym 0 is reserved
-               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;
+               elfsetupplt();
 
-                               if(!s->dynexport) {
-                                       d = lookup(".rel", 0);
-                                       addaddr(d, s);
-                                       adduint32(d, ELF32_R_INFO(nsym, R_386_32));
-                               }
-
-                               nsym++;
-
-                               d = lookup(".dynsym", 0);
-                               adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
-                               /* value */
-                               if(!s->dynexport)
-                                       adduint32(d, 0);
-                               else
-                                       addaddr(d, s);
-
-                               /* size of object */
-                               adduint32(d, 0);
-
-                               /* type */
-                               t = STB_GLOBAL << 4;
-                               if(s->dynexport && s->type == STEXT)
-                                       t |= STT_FUNC;
-                               else
-                                       t |= STT_OBJECT;
-                               adduint8(d, t);
-
-                               /* reserved */
-                               adduint8(d, 0);
-
-                               /* section where symbol is defined */
-                               if(!s->dynexport)
-                                       adduint16(d, SHN_UNDEF);
-                               else {
-                                       switch(s->type) {
-                                       default:
-                                       case STEXT:
-                                               t = 9;
-                                               break;
-                                       case SDATA:
-                                               t = 10;
-                                               break;
-                                       case SBSS:
-                                               t = 11;
-                                               break;
-                                       }
-                                       adduint16(d, t);
-                               }
-
-                               if(!s->dynexport && needlib(s->dynimplib))
-                                       elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
-                       }
-               }
-
-               elfdynhash(nsym);
+               /* define dynamic elf table */
+               s = lookup(".dynamic", 0);
+               s->reachable = 1;
+               s->type = SELFDATA;
 
                /*
                 * .dynamic table
                 */
-               s = dynamic;
                elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
                elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
                elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
@@ -305,6 +629,10 @@ doelf(void)
                elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
                if(rpath)
                        elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+               elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+               elfwritedynent(s, DT_PLTREL, DT_REL);
+               elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
+               elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
                elfwritedynent(s, DT_NULL, 0);
        }
 }
@@ -365,6 +693,14 @@ asmb(void)
        if(HEADTYPE == 6)
                machlink = domacholink();
 
+       if(iself) {
+               /* index of elf text section; needed by asmelfsym, double-checked below */
+               /* !debug['d'] causes extra sections before the .text section */
+               elftextsh = 1;
+               if(!debug['d'])
+                       elftextsh += 10;
+       }
+
        symsize = 0;
        spsize = 0;
        lcsize = 0;
@@ -635,6 +971,22 @@ asmb(void)
                        sh->flags = SHF_ALLOC;
                        sh->addralign = 1;
                        shsym(sh, lookup(".dynstr", 0));
+                       
+                       sh = newElfShdr(elfstr[ElfStrRelPlt]);
+                       sh->type = SHT_REL;
+                       sh->flags = SHF_ALLOC;
+                       sh->entsize = ELF32RELSIZE;
+                       sh->addralign = 4;
+                       sh->link = dynsym;
+                       sh->info = eh->shnum;   // .plt
+                       shsym(sh, lookup(".rel.plt", 0));
+                       
+                       sh = newElfShdr(elfstr[ElfStrPlt]);
+                       sh->type = SHT_PROGBITS;
+                       sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+                       sh->entsize = 4;
+                       sh->addralign = 4;
+                       shsym(sh, lookup(".plt", 0));
 
                        sh = newElfShdr(elfstr[ElfStrHash]);
                        sh->type = SHT_HASH;
@@ -682,6 +1034,8 @@ asmb(void)
                ph->flags = PF_W+PF_R;
                ph->align = 4;
 
+               if(elftextsh != eh->shnum)
+                       diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
                for(sect=segtext.sect; sect!=nil; sect=sect->next)
                        elfshbits(sect);
                for(sect=segrodata.sect; sect!=nil; sect=sect->next)
@@ -814,12 +1168,13 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
 
        for(h=0; h<NHASH; h++) {
                for(s=hash[h]; s!=S; s=s->hash) {
-                       switch(s->type) {
+                       switch(s->type&~SSUB) {
                        case SCONST:
                        case SRODATA:
                        case SDATA:
                        case SELFDATA:
                        case SMACHO:
+                       case SMACHOGOT:
                        case SWINDOWS:
                                if(!s->reachable)
                                        continue;
@@ -840,6 +1195,9 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
        }
 
        for(s = textp; s != nil; s = s->next) {
+               if(s->text == nil)
+                       continue;
+
                /* filenames first */
                for(a=s->autom; a; a=a->link)
                        if(a->type == D_FILE)
index a14a2bf2a6b7b0b0610ac1d7aca13e8a2aaba66d..60dd64e848d6ced167c80f40ebf9a9d08506244f 100644 (file)
@@ -84,7 +84,7 @@ struct        Reloc
 {
        int32   off;
        uchar   siz;
-       uchar   type;
+       int32   type;
        int32   add;
        Sym*    sym;
 };
@@ -130,9 +130,13 @@ struct     Sym
        int32   value;
        int32   size;
        int32   sig;
+       int32   dynid;
+       int32   plt;
+       int32   got;
        Sym*    hash;   // in hash table
        Sym*    next;   // in text or data list
        Sym*    sub;    // in sub list
+       Sym*    outer;  // container of sub
        Sym*    gotype;
        char*   file;
        char*   dynimpname;
@@ -165,16 +169,23 @@ enum
        /* order here is order in output file */
        STEXT,
        SELFDATA,
+       SMACHOPLT,
        SRODATA,
        SDATA,
        SMACHO, /* Mach-O __nl_symbol_ptr */
+       SMACHOGOT,
        SWINDOWS,
        SBSS,
 
        SXREF,
+       SMACHODYNSTR,
+       SMACHODYNSYM,
+       SMACHOINDIRECTPLT,
+       SMACHOINDIRECTGOT,
        SFILE,
        SCONST,
-       
+       SDYNIMPORT,
+
        SSUB = 1<<8,    /* sub-symbol, linked from parent via ->sub list */
 
        NHASH           = 10007,
@@ -317,7 +328,7 @@ EXTERN      int     dtype;
 EXTERN int     tlsoffset;
 EXTERN Sym*    adrgotype;      // type symbol on last Adr read
 EXTERN Sym*    fromgotype;     // type symbol on last p->from read
-
+EXTERN int     elftextsh;
 
 extern Optab   optab[];
 extern char*   anames[];
index f2081178c072d6cca24870fb78fb1606115b9f24..c1e455c340aead7f52f5a6f2e0eae2927ac08bfc 100644 (file)
@@ -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;
@@ -212,6 +236,33 @@ reloc(void)
                relocsym(s);
 }
 
+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)
 {
@@ -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,9 +641,37 @@ 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)
 {
@@ -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) {
index deaf6a2d8db2ffccfcbb0776495a713000c611b7..d5b0b03111ae2c58a3f511f3987b602ec767ff7e 100644 (file)
@@ -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*
index aecbe8612ac4d9d39ca77d8b254e8e1fc2ac6751..607cc3f3adebc5c757123261f3a0719e96b2f3cf 100644 (file)
@@ -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*
index e666515c041a55aaa521f32fd8481422efb7d6fb..0aefb3e92bbecef63fde152f63b5d2f42cc33ab9 100644 (file)
@@ -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 };
index 57a565e808a32bb7e490e06cb3bdd54634678847..f11cb34f6685907e89f4cabfe60a471d08330fa4 100644 (file)
@@ -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 {
index 67264233c7779efd4d08da607ab95cf3d364f0dd..45bdd4cefcd790262d4d8d73462dd57d98df41b8 100644 (file)
@@ -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;
-
-       ptrsize = 4;
-       if(macho64)
-               ptrsize = 8;
-
-       // 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;
-               }
-       }
+       Sym *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;
-       }
+       if(debug['d'])
+               return;
 
-       smacho->size = (nexpsym+nimpsym) * ptrsize;
-       if(smacho->size == 0)
-               smacho->reachable = 0;
+       // empirically, string table must begin with " \x00".
+       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);
+}
index 524e7ae4e87f98193309a2d61ca33909a67447b3..03f1d2c3216f30821312e7cbda5a83c6521c4640 100644 (file)
@@ -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);