]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/5l, cmd/ld: dynamic linking library support
authorShenghou Ma <minux.ma@gmail.com>
Fri, 4 May 2012 10:14:26 +0000 (18:14 +0800)
committerShenghou Ma <minux.ma@gmail.com>
Fri, 4 May 2012 10:14:26 +0000 (18:14 +0800)
        Part 1 of CL 5601044 (cgo: Linux/ARM support)
        Limitation: doesn't support thumb library yet.

R=golang-dev, dave, rsc
CC=golang-dev
https://golang.org/cl/5991065

src/cmd/5l/5.out.h
src/cmd/5l/asm.c
src/cmd/5l/l.h
src/cmd/5l/obj.c
src/cmd/5l/pass.c
src/cmd/5l/span.c
src/cmd/ld/data.c
src/cmd/ld/elf.h
src/cmd/ld/ldelf.c

index 3755858825b1e6c2036739610ef11903bcef70a3..08a60d0642c12a25976df6d79832b4df6812f77e 100644 (file)
@@ -254,6 +254,12 @@ enum       as
 /* internal only */
 #define        D_SIZE          (D_NONE+40)
 #define        D_PCREL         (D_NONE+41)
+#define        D_GOTOFF        (D_NONE+42) // R_ARM_GOTOFF
+#define        D_PLT0          (D_NONE+43) // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000
+#define        D_PLT1          (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
+#define        D_PLT2          (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
+#define        D_PLT32         (D_NONE+46) // R_ARM_PLT32, bl xxxxx
+#define        D_CALL          (D_NONE+47) // R_ARM_CALL, bl xxxxx
 
 /*
  * this is the ranlib header
index 538e2c54c5acb5677d6d1c14707f4b0c8820dc16..b4798b94677c2da0203dc77869c48e8cfcee5703 100644 (file)
@@ -36,7 +36,7 @@
 
 static Prog *PP;
 
-char linuxdynld[] = "/lib/ld-linux.so.2";
+char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
 
 int32
 entryvalue(void)
@@ -73,6 +73,8 @@ enum {
        ElfStrShstrtab,
        ElfStrRelPlt,
        ElfStrPlt,
+       ElfStrGnuVersion,
+       ElfStrGnuVersionR,
        ElfStrNoteNetbsdIdent,
        ElfStrNoPtrData,
        ElfStrNoPtrBss,
@@ -103,36 +105,354 @@ needlib(char *name)
 
 int    nelfsym = 1;
 
-void
-adddynrel(Sym *s, Reloc *r)
+static void    addpltsym(Sym*);
+static void    addgotsym(Sym*);
+static void    addgotsyminternal(Sym*);
+
+// Preserve highest 8 bits of a, and do addition to lower 24-bit
+// of a and b; used to adjust ARM branch intruction's target
+static int32
+braddoff(int32 a, int32 b)
 {
-       USED(s);
-       USED(r);
-       diag("adddynrel: unsupported binary format");
+       return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b));
 }
 
 void
-adddynsym(Sym *s)
+adddynrel(Sym *s, Reloc *r)
 {
-       USED(s);
-       diag("adddynsym: not implemented");
+       Sym *targ, *rel;
+
+       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_ARM_PLT32:
+               r->type = D_PLT32;
+               if(targ->dynimpname != nil && !targ->dynexport) {
+                       addpltsym(targ);
+                       r->sym = lookup(".plt", 0);
+                       r->add = braddoff(r->add, targ->plt / 4);
+               }
+               return;
+
+       case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL
+               diag("R_ARM_THM_CALL, are you using -marm?");
+               errorexit();
+               return;
+
+       case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
+               if(targ->dynimpname == nil || targ->dynexport) {
+                       addgotsyminternal(targ);
+               } else {
+                       addgotsym(targ);
+               }
+               r->type = D_CONST;      // write r->add during relocsym
+               r->sym = S;
+               r->add += targ->got;
+               return;
+       
+       case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32
+               r->type = D_GOTOFF;
+               return;
+       
+       case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
+               r->type = D_PCREL;
+               r->sym = lookup(".got", 0);
+               r->add += 4;
+               return;
+
+       case 256 + R_ARM_CALL:
+               r->type = D_CALL;
+               r->add += 0;
+               return;
+
+       case 256 + R_ARM_REL32: // R_ARM_REL32
+               r->type = D_PCREL;
+               r->add += 4;
+               return;
+
+       case 256 + R_ARM_ABS32: 
+               if(targ->dynimpname != nil && !targ->dynexport)
+                       diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
+               r->type = D_ADDR;
+               return;
+
+       case 256 + R_ARM_V4BX:
+               // we can just ignore this, because we are targeting ARM V5+ anyway
+               if(r->sym) {
+                       // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
+                       r->sym->type = 0;
+               }
+               r->sym = S;
+               return;
+       }
+       
+       // Handle references to ELF symbols from our own object files.
+       if(targ->dynimpname == nil || targ->dynexport)
+               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_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
+                       r->type = D_CONST;      // write r->add during relocsym
+                       r->sym = S;
+                       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)
 {
-       // TODO
+       Sym *plt, *got;
+       
+       plt = lookup(".plt", 0);
+       got = lookup(".got.plt", 0);
+       if(plt->size == 0) {
+               // str lr, [sp, #-4]!
+               adduint32(plt, 0xe52de004);
+               // ldr lr, [pc, #4]
+               adduint32(plt, 0xe59fe004);
+               // add lr, pc, lr
+               adduint32(plt, 0xe08fe00e);
+               // ldr pc, [lr, #8]!
+               adduint32(plt, 0xe5bef008);
+               // .word &GLOBAL_OFFSET_TABLE[0] - .
+               addpcrelplus(plt, got, 4);
+
+               // the first .plt entry requires 3 .plt.got entries
+               adduint32(got, 0);
+               adduint32(got, 0);
+               adduint32(got, 0);
+       }
 }
 
 int
 archreloc(Reloc *r, Sym *s, vlong *val)
 {
-       USED(r);
-       USED(s);
-       USED(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;
+       // The following three arch specific relocations are only for generation of 
+       // Linux/ARM ELF's PLT entry (3 assembler instruction)
+       case D_PLT0: // add ip, pc, #0xXX00000
+               if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0)))
+                       diag(".got.plt should be placed after .plt section.");
+               *val = 0xe28fc600U +
+                       (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20));
+               return 0;
+       case D_PLT1: // add ip, ip, #0xYY000
+               *val = 0xe28cca00U +
+                       (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12));
+               return 0;
+       case D_PLT2: // ldr pc, [ip, #0xZZZ]!
+               *val = 0xe5bcf000U +
+                       (0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8));
+               return 0;
+       case D_PLT32: // bl XXXXXX or b YYYYYY in R_ARM_PLT32
+               *val = (0xff000000U & (uint32)r->add) +
+                       (0xffffff & (uint32)((symaddr(r->sym) + (0xffffffU & (uint32)r->add) * 4) - (s->value + r->off)) / 4);
+               return 0;
+       case D_CALL: // bl XXXXXX
+               *val = braddoff(0xeb000000U, (0xffffff & (uint32)((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4)));
+               return 0;
+       }
        return -1;
 }
 
+static Reloc *
+addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
+{
+       Reloc *r;
+       r = addrel(plt);
+       r->sym = got;
+       r->off = plt->size;
+       r->siz = 4;
+       r->type = typ;
+       r->add = sym->got - 8;
+
+       plt->reachable = 1;
+       plt->size += 4;
+       symgrow(plt, plt->size);
+
+       return r;
+}
+
+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", 0);
+               if(plt->size == 0)
+                       elfsetupplt();
+               
+               // .got entry
+               s->got = got->size;
+               adduint32(got, 0);
+
+               // .plt entry, this depends on the .got entry
+               s->plt = plt->size;
+               addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000
+               addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000
+               addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]!
+
+               // rel
+               addaddrplus(rel, got, s->got);
+               adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
+       } else {
+               diag("addpltsym: unsupported binary format");
+       }
+}
+
+static void
+addgotsyminternal(Sym *s)
+{
+       Sym *got;
+       
+       if(s->got >= 0)
+               return;
+
+       got = lookup(".got", 0);
+       s->got = got->size;
+
+       addaddrplus(got, s, 0);
+
+       if(iself) {
+               ;
+       } else {
+               diag("addgotsyminternal: 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_ARM_GLOB_DAT));
+       } else {
+               diag("addgotsym: unsupported binary format");
+       }
+}
+
+void
+adddynsym(Sym *s)
+{
+       Sym *d;
+       int t;
+       char *name;
+
+       if(s->dynid >= 0)
+               return;
+
+       if(s->dynimpname == nil) {
+               s->dynimpname = s->name;
+               //diag("adddynsym: no dynamic name for %s", s->name);
+       }
+
+       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 {
+               diag("adddynsym: unsupported binary format");
+       }
+}
+
 void
 adddynlib(char *lib)
 {
@@ -175,7 +495,7 @@ doelf(void)
        addstring(shstrtab, ".rodata");
        addstring(shstrtab, ".gosymtab");
        addstring(shstrtab, ".gopclntab");
-       if(!debug['s']) {       
+       if(!debug['s']) {
                elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
                elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
        }
@@ -192,17 +512,19 @@ doelf(void)
                elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
                elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
                elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
+               elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
+               elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
 
                /* dynamic symbol table - first entry all zeros */
                s = lookup(".dynsym", 0);
                s->type = SELFROSECT;
                s->reachable = 1;
-               s->value += ELF32SYMSIZE;
+               s->size += ELF32SYMSIZE;
 
                /* dynamic string table */
                s = lookup(".dynstr", 0);
-               s->type = SELFROSECT;
                s->reachable = 1;
+               s->type = SELFROSECT;
                if(s->size == 0)
                        addstring(s, "");
                dynstr = s;
@@ -234,7 +556,15 @@ doelf(void)
                s = lookup(".rel.plt", 0);
                s->reachable = 1;
                s->type = SELFROSECT;
-               
+
+               s = lookup(".gnu.version", 0);
+               s->reachable = 1;
+               s->type = SELFROSECT;
+
+               s = lookup(".gnu.version_r", 0);
+               s->reachable = 1;
+               s->type = SELFROSECT;
+
                elfsetupplt();
 
                /* define dynamic elf table */
@@ -259,8 +589,9 @@ doelf(void)
                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_DEBUG, 0);
-               elfwritedynent(s, DT_NULL, 0);
+               // elfdynhash will finish it
        }
 }
 
@@ -335,7 +666,7 @@ asmb(void)
                /* !debug['d'] causes extra sections before the .text section */
                elftextsh = 2;
                if(!debug['d']) {
-                       elftextsh += 10;
+                       elftextsh += 9;
                        if(elfverneed)
                                elftextsh += 2;
                }
@@ -520,12 +851,13 @@ asmb(void)
                /* Dynamic linking sections */
                if(!debug['d']) {       /* -d suppresses dynamic loader format */
                        /* S headers for dynamic linking */
-                       sh = newElfShdr(elfstr[ElfStrGot]);
+                       // ARM ELF needs .plt to be placed before .got
+                       sh = newElfShdr(elfstr[ElfStrPlt]);
                        sh->type = SHT_PROGBITS;
-                       sh->flags = SHF_ALLOC+SHF_WRITE;
+                       sh->flags = SHF_ALLOC+SHF_EXECINSTR;
                        sh->entsize = 4;
                        sh->addralign = 4;
-                       shsym(sh, lookup(".got", 0));
+                       shsym(sh, lookup(".plt", 0));
 
                        sh = newElfShdr(elfstr[ElfStrGotPlt]);
                        sh->type = SHT_PROGBITS;
@@ -534,6 +866,13 @@ asmb(void)
                        sh->addralign = 4;
                        shsym(sh, lookup(".got.plt", 0));
 
+                       sh = newElfShdr(elfstr[ElfStrGot]);
+                       sh->type = SHT_PROGBITS;
+                       sh->flags = SHF_ALLOC+SHF_WRITE;
+                       sh->entsize = 4;
+                       sh->addralign = 4;
+                       shsym(sh, lookup(".got", 0));
+
                        dynsym = eh->shnum;
                        sh = newElfShdr(elfstr[ElfStrDynsym]);
                        sh->type = SHT_DYNSYM;
@@ -550,6 +889,24 @@ asmb(void)
                        sh->addralign = 1;
                        shsym(sh, lookup(".dynstr", 0));
 
+                       if(elfverneed) {
+                               sh = newElfShdr(elfstr[ElfStrGnuVersion]);
+                               sh->type = SHT_GNU_VERSYM;
+                               sh->flags = SHF_ALLOC;
+                               sh->addralign = 2;
+                               sh->link = dynsym;
+                               sh->entsize = 2;
+                               shsym(sh, lookup(".gnu.version", 0));
+
+                               sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
+                               sh->type = SHT_GNU_VERNEED;
+                               sh->flags = SHF_ALLOC;
+                               sh->addralign = 4;
+                               sh->info = elfverneed;
+                               sh->link = dynsym+1;  // dynstr
+                               shsym(sh, lookup(".gnu.version_r", 0));
+                       }
+
                        sh = newElfShdr(elfstr[ElfStrHash]);
                        sh->type = SHT_HASH;
                        sh->flags = SHF_ALLOC;
@@ -574,14 +931,12 @@ asmb(void)
                        sh->addralign = 4;
                        sh->link = dynsym+1;    // dynstr
                        shsym(sh, lookup(".dynamic", 0));
-
                        ph = newElfPhdr();
                        ph->type = PT_DYNAMIC;
                        ph->flags = PF_R + PF_W;
                        phsh(ph, sh);
 
-                       /*
-                        * Thread-local storage segment (really just size).
+                       // .tbss (optional) and TLS phdr
                        if(tlsoffset != 0) {
                                ph = newElfPhdr();
                                ph->type = PT_TLS;
@@ -589,7 +944,6 @@ asmb(void)
                                ph->memsz = -tlsoffset;
                                ph->align = 4;
                        }
-                        */
                }
 
                ph = newElfPhdr();
@@ -1849,7 +2203,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
                for(s=hash[h]; s!=S; s=s->hash) {
                        if(s->hide)
                                continue;
-                       switch(s->type) {
+                       switch(s->type&~SSUB) {
                        case SCONST:
                        case SRODATA:
                        case SDATA:
@@ -1882,6 +2236,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 b1a48ded89c7b48bdd0292cee1c7b502274461b7..911f63e12f57f04084c74e9a6be825d5547f8969 100644 (file)
@@ -303,6 +303,7 @@ EXTERN      int     version;
 EXTERN char    xcmp[C_GOK+1][C_GOK+1];
 EXTERN Prog    zprg;
 EXTERN int     dtype;
+EXTERN int     tlsoffset;
 EXTERN int     armsize;
 
 extern char*   anames[];
index fe6bc2e7e170b285764a90f902fb6926727ce635..7dc5b899b6257fcbea9bdd094ed9b636f76f33a8 100644 (file)
@@ -205,7 +205,9 @@ main(int argc, char *argv[])
                        INITRND = 1024;
                break;
        case Hlinux:    /* arm elf */
-               debug['d'] = 1; // no dynamic linking
+               debug['d'] = 0; // with dynamic linking
+               tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
+                               // this number is known to ../../pkg/runtime/cgo/gcc_linux_arm.c
                elfinit();
                HEADR = ELFRESERVE;
                if(INITTEXT == -1)
@@ -263,6 +265,8 @@ main(int argc, char *argv[])
        noops();
        dostkcheck();
        span();
+       addexport();
+       // textaddress() functionality is handled in span()
        pclntab();
        symtab();
        dodata();
index 0f2afbd850de0365c78646ca9a4715ce7655e337..cf6db8f0209a2ac75ddcea8fe23025ca9785dab9 100644 (file)
@@ -215,7 +215,7 @@ patch(void)
                                s = p->to.sym;
                                if(s->text == nil)
                                        continue;
-                               switch(s->type) {
+                               switch(s->type&~SSUB) {
                                default:
                                        diag("undefined: %s", s->name);
                                        s->type = STEXT;
@@ -231,7 +231,7 @@ patch(void)
                        if(p->to.type != D_BRANCH)
                                continue;
                        c = p->to.offset;
-                       for(q = textp->text; q != P;) {
+                       for(q = cursym->text; q != P;) {
                                if(c == q->pc)
                                        break;
                                if(q->forwd != P && c >= q->forwd->pc)
index bf14ef546b55b82abe127cea5acc94bf5b49cc7e..242ba1603d0f4d26d45b18d586ddee4c6ddc4627 100644 (file)
@@ -90,6 +90,7 @@ span(void)
        int32 c, otxt, out[6];
        Section *sect;
        uchar *bp;
+       Sym *sub;
 
        if(debug['v'])
                Bprint(&bso, "%5.2f span\n", cputime());
@@ -100,6 +101,20 @@ span(void)
        otxt = c;
        for(cursym = textp; cursym != nil; cursym = cursym->next) {
                p = cursym->text;
+               if(p == P || p->link == P) { // handle external functions and ELF section symbols
+                       if(cursym->type & SSUB)
+                               continue;
+                       if(cursym->align != 0)
+                               c = rnd(c, cursym->align);
+                       cursym->value = 0;
+                       for(sub = cursym; sub != S; sub = sub->sub) {
+                               sub->value += c;
+                               for(p = sub->text; p != P; p = p->link)
+                                       p->pc += sub->value;
+                       }
+                       c += cursym->size;
+                       continue;
+               }
                p->pc = c;
                cursym->value = c;
 
@@ -160,6 +175,8 @@ span(void)
                bflag = 0;
                c = INITTEXT;
                for(cursym = textp; cursym != nil; cursym = cursym->next) {
+                       if(!cursym->text || !cursym->text->link)
+                               continue;
                        cursym->value = c;
                        for(p = cursym->text; p != P; p = p->link) {
                                curp = p;
@@ -217,6 +234,8 @@ span(void)
         */
        for(cursym = textp; cursym != nil; cursym = cursym->next) {
                p = cursym->text;
+               if(p == P || p->link == P)
+                      continue;
                autosize = p->to.offset + 4;
                symgrow(cursym, cursym->size);
        
@@ -407,25 +426,9 @@ immhalf(int32 v)
 int32
 symaddr(Sym *s)
 {
-       int32 v;
-
-       v = s->value;
-       switch(s->type) {
-       default:
-               diag("unexpected type %d in symaddr(%s)", s->type, s->name);
-               return 0;
-       
-       case STEXT:
-       case SELFROSECT:
-       case SRODATA:
-       case SDATA:
-       case SBSS:
-       case SCONST:
-       case SNOPTRDATA:
-       case SNOPTRBSS:
-               break;
-       }
-       return v;
+       if(!s->reachable)
+               diag("unreachable symbol in symaddr - %s", s->name);
+       return s->value;
 }
 
 int
index 786c10b64d838707d7b86637a3552334c4b790a2..ea7129781ef364029e3f34f8ce05e77b28f508f1 100644 (file)
@@ -282,7 +282,7 @@ dynrelocsym(Sym *s)
        }
 
        for(r=s->r; r<s->r+s->nr; r++)
-               if(r->sym->type == SDYNIMPORT || r->type >= 256)
+               if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
                        adddynrel(s, r);
 }
 
index 690ade9753dbea83ab364be0ba3ecd1bb7a598da..e319ad25b4527bf321f90cbee2fa159c3d273b5d 100644 (file)
@@ -562,6 +562,8 @@ typedef struct {
 #define        R_ARM_GOTPC             25      /* Add PC-relative GOT table address. */
 #define        R_ARM_GOT32             26      /* Add PC-relative GOT offset. */
 #define        R_ARM_PLT32             27      /* Add PC-relative PLT offset. */
+#define        R_ARM_CALL              28
+#define        R_ARM_V4BX              40
 #define        R_ARM_GNU_VTENTRY       100
 #define        R_ARM_GNU_VTINHERIT     101
 #define        R_ARM_RSBREL32          250
index bd4f3e7d871e54b9f03b5f8012217ccf950a1d81..b64b5e5653d668cb3eeb70be625474225135ecb9 100644 (file)
@@ -588,14 +588,18 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
                                        p += 4;
                                }
                        }
-                       if(readsym(obj, info>>32, &sym) < 0)
-                               goto bad;
-                       if(sym.sym == nil) {
-                               werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
-                                       sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
-                               goto bad;
+                       if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol
+                               rp->sym = S;
+                       } else {
+                               if(readsym(obj, info>>32, &sym) < 0)
+                                       goto bad;
+                               if(sym.sym == nil) {
+                                       werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
+                                               sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
+                                       goto bad;
+                               }
+                               rp->sym = sym.sym;
                        }
-                       rp->sym = sym.sym;
                        rp->type = reltype(pn, (uint32)info, &rp->siz);
                        if(rela)
                                rp->add = add;
@@ -633,6 +637,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
                }
                if(sym.shndx >= obj->nsect || sym.shndx == 0)
                        continue;
+               if(thechar == '5' && (strcmp(sym.name, "$a") == 0 || strcmp(sym.name, "$d") == 0)) // binutils for arm generate these mapping symbols, skip these
+                       continue;
                sect = obj->sect+sym.shndx;
                if(sect->sym == nil) {
                        diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
@@ -715,6 +721,9 @@ readsym(ElfObj *obj, int i, ElfSym *sym)
                werrstr("invalid elf symbol index");
                return -1;
        }
+       if(i == 0) {
+               diag("readym: read null symbol!");
+       }
 
        if(obj->is64) {
                ElfSymBytes64 *b;
@@ -760,7 +769,8 @@ readsym(ElfObj *obj, int i, ElfSym *sym)
                        }
                        // fall through
                case ElfSymBindLocal:
-                       s = lookup(sym->name, version);
+                       if(!(thechar == '5' && (strcmp(sym->name, "$a") == 0 || strcmp(sym->name, "$d") == 0))) // binutils for arm generate these mapping symbols, ignore these
+                               s = lookup(sym->name, version);
                        break;
                default:
                        werrstr("%s: invalid symbol binding %d", sym->name, sym->bind);
@@ -797,6 +807,15 @@ reltype(char *pn, int elftype, uchar *siz)
        switch(R(thechar, elftype)) {
        default:
                diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
+       case R('5', R_ARM_ABS32):
+       case R('5', R_ARM_GOT32):
+       case R('5', R_ARM_PLT32):
+       case R('5', R_ARM_GOTOFF):
+       case R('5', R_ARM_GOTPC):
+       case R('5', R_ARM_THM_PC22):
+       case R('5', R_ARM_REL32):
+       case R('5', R_ARM_CALL):
+       case R('5', R_ARM_V4BX):
        case R('6', R_X86_64_PC32):
        case R('6', R_X86_64_PLT32):
        case R('6', R_X86_64_GOTPCREL):