From 452a9e452b8a88de95b343e13107782aa26c1ed2 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 4 May 2012 18:14:26 +0800 Subject: [PATCH] cmd/5l, cmd/ld: dynamic linking library support 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 | 6 + src/cmd/5l/asm.c | 411 ++++++++++++++++++++++++++++++++++++++++++--- src/cmd/5l/l.h | 1 + src/cmd/5l/obj.c | 6 +- src/cmd/5l/pass.c | 4 +- src/cmd/5l/span.c | 41 ++--- src/cmd/ld/data.c | 2 +- src/cmd/ld/elf.h | 2 + src/cmd/ld/ldelf.c | 35 +++- 9 files changed, 450 insertions(+), 58 deletions(-) diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h index 3755858825..08a60d0642 100644 --- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -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 diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 538e2c54c5..b4798b9467 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -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) diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index b1a48ded89..911f63e12f 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -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[]; diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index fe6bc2e7e1..7dc5b899b6 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -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(); diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c index 0f2afbd850..cf6db8f020 100644 --- a/src/cmd/5l/pass.c +++ b/src/cmd/5l/pass.c @@ -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) diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c index bf14ef546b..242ba1603d 100644 --- a/src/cmd/5l/span.c +++ b/src/cmd/5l/span.c @@ -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 diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 786c10b64d..ea7129781e 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -282,7 +282,7 @@ dynrelocsym(Sym *s) } for(r=s->r; rr+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); } diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index 690ade9753..e319ad25b4 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -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 diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c index bd4f3e7d87..b64b5e5653 100644 --- a/src/cmd/ld/ldelf.c +++ b/src/cmd/ld/ldelf.c @@ -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): -- 2.48.1