int archreloc(Reloc *r, Sym *s, vlong *val) { USED(s); 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; }
void shsym(Elf64_Shdr *sh, Sym *s) { sh->addr = symaddr(s); sh->off = datoff(sh->addr); sh->size = s->size; }
int archreloc(Reloc *r, LSym *s, vlong *val) { USED(s); if(linkmode == LinkExternal) return -1; switch(r->type) { case D_CONST: *val = r->add; return 0; case D_GOTOFF: *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); return 0; } return -1; }
void shsym(ElfShdr *sh, Sym *s) { vlong addr; addr = symaddr(s); if(sh->flags&SHF_ALLOC) sh->addr = addr; sh->off = datoff(addr); sh->size = s->size; }
void relocsym(Sym *s) { Reloc *r; Prog p; int32 i, off, siz, fl; 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) diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, 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: o = 0; if(archreloc(r, s, &o) < 0) diag("unknown reloc %d", r->type); break; case D_ADDR: o = symaddr(r->sym) + r->add; break; case D_PCREL: // r->sym can be null when CALL $(constant) is transformed from absoulte PC to relative PC call. o = 0; if(r->sym) o += symaddr(r->sym); o += r->add - (s->value + r->off + r->siz); break; case D_SIZE: o = r->sym->size + r->add; break; } //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: cursym = s; diag("bad reloc size %#ux for %s", siz, r->sym->name); case 4 + Rbig: fl = o; s->p[off] = fl>>24; s->p[off+1] = fl>>16; s->p[off+2] = fl>>8; s->p[off+3] = fl; break; case 4 + Rlittle: fl = o; s->p[off] = fl; s->p[off+1] = fl>>8; s->p[off+2] = fl>>16; s->p[off+3] = fl>>24; break; case 4: fl = o; cast = (uchar*)&fl; for(i=0; i<4; i++) s->p[off+i] = cast[inuxi4[i]]; break; case 8: cast = (uchar*)&o; for(i=0; i<8; i++) s->p[off+i] = cast[inuxi8[i]]; break; } } }
void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) { Auto *a; Sym *s; int h; s = lookup("etext", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); for(h=0; h<NHASH; h++) { for(s=hash[h]; s!=S; s=s->hash) { if(s->hide) continue; switch(s->type&SMASK) { case SCONST: case SRODATA: case SDATA: case SELFROSECT: case SMACHO: case SMACHOGOT: case STYPE: case SSTRING: case SGOSTRING: case SWINDOWS: case SNOPTRDATA: case SSYMTAB: case SPCLNTAB: case SGCDATA: case SGCBSS: if(!s->reachable) continue; put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); continue; case SBSS: case SNOPTRBSS: if(!s->reachable) continue; put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype); continue; case SFILE: put(nil, s->name, 'f', s->value, 0, s->version, 0); continue; } } } 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) put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0); else if(a->type == D_FILE1) put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0); 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+4, 0, 0, 0); for(a=s->autom; a; a=a->link) if(a->type == D_AUTO) put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype); else if(a->type == D_PARAM) put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype); } if(debug['v'] || debug['n']) Bprint(&bso, "symsize = %d\n", symsize); Bflush(&bso); }
void relocsym(Sym *s) { Reloc *r; Sym *rs; Prog p; int32 i, off, siz, fl; vlong o; uchar *cast; cursym = s; memset(&p, 0, sizeof p); for(r=s->r; r<s->r+s->nr; r++) { r->done = 1; off = r->off; siz = r->siz; if(off < 0 || off+siz > s->np) { diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np); continue; } if(r->sym != S && (r->sym->type & SMASK == 0 || r->sym->type & SMASK == SXREF)) { diag("%s: not defined", r->sym->name); continue; } if(r->type >= 256) continue; if(r->sym != S && r->sym->type == SDYNIMPORT) diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, 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: o = 0; if(linkmode == LinkExternal || archreloc(r, s, &o) < 0) diag("unknown reloc %d", r->type); break; case D_ADDR: if(linkmode == LinkExternal && r->sym->type != SCONST) { r->done = 0; // set up addend for eventual relocation via outer symbol. rs = r->sym; r->xadd = r->add; while(rs->outer != nil) { r->xadd += symaddr(rs) - symaddr(rs->outer); rs = rs->outer; } if(rs->type != SHOSTOBJ && rs->sect == nil) diag("missing section for %s", rs->name); r->xsym = rs; o = r->xadd; if(iself) { if(thechar == '6') o = 0; } else if(HEADTYPE == Hdarwin) { if(rs->type != SHOSTOBJ) o += symaddr(rs); } else { diag("unhandled pcrel relocation for %s", headtype); } break; } o = symaddr(r->sym) + r->add; break; case D_PCREL: // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) { r->done = 0; // set up addend for eventual relocation via outer symbol. rs = r->sym; r->xadd = r->add; while(rs->outer != nil) { r->xadd += symaddr(rs) - symaddr(rs->outer); rs = rs->outer; } r->xadd -= r->siz; // relative to address after the relocated chunk if(rs->type != SHOSTOBJ && rs->sect == nil) diag("missing section for %s", rs->name); r->xsym = rs; o = r->xadd; if(iself) { if(thechar == '6') o = 0; } else if(HEADTYPE == Hdarwin) { if(rs->type != SHOSTOBJ) o += symaddr(rs) - rs->sect->vaddr; o -= r->off; // WTF? } else { diag("unhandled pcrel relocation for %s", headtype); } break; } o = 0; if(r->sym) o += symaddr(r->sym); o += r->add - (s->value + r->off + r->siz); break; case D_SIZE: o = r->sym->size + r->add; break; } //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: cursym = s; diag("bad reloc size %#ux for %s", siz, r->sym->name); case 4: fl = o; cast = (uchar*)&fl; for(i=0; i<4; i++) s->p[off+i] = cast[inuxi4[i]]; break; case 8: cast = (uchar*)&o; for(i=0; i<8; i++) s->p[off+i] = cast[inuxi8[i]]; break; } } }
// assign addresses void address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss, *datarelro; Section *typelink; Sym *sym, *sub; uvlong va; vlong vlen; va = INITTEXT; segtext.rwx = 05; segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { va = rnd(va, s->align); s->vaddr = va; va += s->len; } segtext.len = va - INITTEXT; segtext.filelen = segtext.len; va = rnd(va, INITRND); segdata.rwx = 06; segdata.vaddr = va; segdata.fileoff = va - segtext.vaddr + segtext.fileoff; segdata.filelen = 0; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32) segdata.fileoff = segtext.fileoff + segtext.filelen; data = nil; noptr = nil; bss = nil; noptrbss = nil; datarelro = nil; for(s=segdata.sect; s != nil; s=s->next) { vlen = s->len; if(s->next) vlen = s->next->vaddr - s->vaddr; s->vaddr = va; va += vlen; segdata.len = va - segdata.vaddr; if(strcmp(s->name, ".data") == 0) data = s; if(strcmp(s->name, ".noptrdata") == 0) noptr = s; if(strcmp(s->name, ".bss") == 0) bss = s; if(strcmp(s->name, ".noptrbss") == 0) noptrbss = s; if(strcmp(s->name, ".data.rel.ro") == 0) datarelro = s; } segdata.filelen = bss->vaddr - segdata.vaddr; text = segtext.sect; rodata = text->next; typelink = rodata->next; symtab = typelink->next; pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { cursym = sym; if(sym->type < SNOPTRDATA) sym->value += rodata->vaddr; else sym->value += segdata.sect->vaddr; for(sub = sym->sub; sub != nil; sub = sub->sub) sub->value += sym->value; } xdefine("text", STEXT, text->vaddr); xdefine("etext", STEXT, text->vaddr + text->len); xdefine("rodata", SRODATA, rodata->vaddr); xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); xdefine("typelink", SRODATA, typelink->vaddr); xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len); if(datarelro != nil) { xdefine("datarelro", SRODATA, datarelro->vaddr); xdefine("edatarelro", SRODATA, datarelro->vaddr + datarelro->len); } sym = lookup("gcdata", 0); xdefine("egcdata", STYPE, symaddr(sym) + sym->size); lookup("egcdata", 0)->sect = sym->sect; sym = lookup("gcbss", 0); xdefine("egcbss", STYPE, symaddr(sym) + sym->size); lookup("egcbss", 0)->sect = sym->sect; xdefine("symtab", SRODATA, symtab->vaddr); xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); xdefine("pclntab", SRODATA, pclntab->vaddr); xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len); xdefine("noptrdata", SNOPTRDATA, noptr->vaddr); xdefine("enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); xdefine("bss", SBSS, bss->vaddr); xdefine("ebss", SBSS, bss->vaddr + bss->len); xdefine("data", SDATA, data->vaddr); xdefine("edata", SDATA, data->vaddr + data->len); xdefine("noptrbss", SNOPTRBSS, noptrbss->vaddr); xdefine("enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); xdefine("end", SBSS, segdata.vaddr + segdata.len); }
void relocsym(Sym *s) { Reloc *r; Sym *rs; Prog p; int32 i, off, siz, fl; 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 > s->np) { diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np); continue; } if(r->sym != S && (r->sym->type & SMASK == 0 || r->sym->type & SMASK == SXREF)) { diag("%s: not defined", r->sym->name); continue; } if(r->type >= 256) continue; if(r->sym != S && r->sym->type == SDYNIMPORT) diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, 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: o = 0; if(isobj || archreloc(r, s, &o) < 0) diag("unknown reloc %d", r->type); break; case D_ADDR: o = symaddr(r->sym) + r->add; if(isobj && r->sym->type != SCONST) { if(thechar == '6') o = 0; else { // set up addend for eventual relocation via outer symbol rs = r->sym; while(rs->outer != nil) rs = rs->outer; o -= symaddr(rs); } } break; case D_PCREL: // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. o = 0; if(r->sym) o += symaddr(r->sym); o += r->add - (s->value + r->off + r->siz); if(isobj && r->sym->type != SCONST) { if(thechar == '6') o = 0; else o = r->add - r->siz; } break; case D_SIZE: o = r->sym->size + r->add; break; } //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: cursym = s; diag("bad reloc size %#ux for %s", siz, r->sym->name); case 4: fl = o; cast = (uchar*)&fl; for(i=0; i<4; i++) s->p[off+i] = cast[inuxi4[i]]; break; case 8: cast = (uchar*)&o; for(i=0; i<8; i++) s->p[off+i] = cast[inuxi8[i]]; break; } } }
/* * Apply a single intra-module relocation to the data. `relbase' is the * target relocation base for the section (i.e. it corresponds to where * r_offset == 0). `dataaddr' is the relocated address corresponding to * the start of the data, and `len' is the number of bytes. */ int __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len) { #ifdef __sparc__ Elf_Size w; const Elf_Rela *a; switch (reltype) { case ELF_RELOC_RELA: a = reldata; if (relbase + a->r_offset >= dataaddr && relbase + a->r_offset < dataaddr + len) { switch (ELF_R_TYPE(a->r_info)) { case R_SPARC_RELATIVE: w = relbase + a->r_addend; bcopy(&w, (u_char *)data + (relbase + a->r_offset - dataaddr), sizeof(w)); break; default: printf("\nunhandled relocation type %u\n", (u_int)ELF_R_TYPE(a->r_info)); return (EFTYPE); } } break; } return (0); #elif (defined(__i386__) || defined(__amd64__)) && __ELF_WORD_SIZE == 64 Elf64_Addr *where, val; Elf_Addr addend, addr; Elf_Size rtype, symidx; const Elf_Rel *rel; const Elf_Rela *rela; switch (reltype) { case ELF_RELOC_REL: rel = (const Elf_Rel *)reldata; where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - dataaddr); addend = 0; rtype = ELF_R_TYPE(rel->r_info); symidx = ELF_R_SYM(rel->r_info); addend = 0; break; case ELF_RELOC_RELA: rela = (const Elf_Rela *)reldata; where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - dataaddr); addend = rela->r_addend; rtype = ELF_R_TYPE(rela->r_info); symidx = ELF_R_SYM(rela->r_info); break; default: return (EINVAL); } if ((char *)where < (char *)data || (char *)where >= (char *)data + len) return (0); if (reltype == ELF_RELOC_REL) addend = *where; /* XXX, definitions not available on i386. */ #define R_X86_64_64 1 #define R_X86_64_RELATIVE 8 switch (rtype) { case R_X86_64_64: /* S + A */ addr = symaddr(ef, symidx); if (addr == 0) return (ESRCH); val = addr + addend; *where = val; break; case R_X86_64_RELATIVE: addr = (Elf_Addr)addend + relbase; val = addr; *where = val; break; default: printf("\nunhandled relocation type %u\n", (u_int)rtype); return (EFTYPE); } return (0); #elif defined(__i386__) && __ELF_WORD_SIZE == 32 Elf_Addr addend, addr, *where, val; Elf_Size rtype, symidx; const Elf_Rel *rel; const Elf_Rela *rela; switch (reltype) { case ELF_RELOC_REL: rel = (const Elf_Rel *)reldata; where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - dataaddr); addend = 0; rtype = ELF_R_TYPE(rel->r_info); symidx = ELF_R_SYM(rel->r_info); addend = 0; break; case ELF_RELOC_RELA: rela = (const Elf_Rela *)reldata; where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - dataaddr); addend = rela->r_addend; rtype = ELF_R_TYPE(rela->r_info); symidx = ELF_R_SYM(rela->r_info); break; default: return (EINVAL); } if ((char *)where < (char *)data || (char *)where >= (char *)data + len) return (0); if (reltype == ELF_RELOC_REL) addend = *where; /* XXX, definitions not available on amd64. */ #define R_386_32 1 /* Add symbol value. */ #define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ #define R_386_RELATIVE 8 /* Add load address of shared object. */ switch (rtype) { case R_386_RELATIVE: addr = addend + relbase; *where = addr; break; case R_386_32: /* S + A */ addr = symaddr(ef, symidx); if (addr == 0) return (ESRCH); val = addr + addend; *where = val; break; default: printf("\nunhandled relocation type %u\n", (u_int)rtype); return (EFTYPE); } return (0); #elif defined(__powerpc__) Elf_Size w; const Elf_Rela *rela; switch (reltype) { case ELF_RELOC_RELA: rela = reldata; if (relbase + rela->r_offset >= dataaddr && relbase + rela->r_offset < dataaddr + len) { switch (ELF_R_TYPE(rela->r_info)) { case R_PPC_RELATIVE: w = relbase + rela->r_addend; bcopy(&w, (u_char *)data + (relbase + rela->r_offset - dataaddr), sizeof(w)); break; default: printf("\nunhandled relocation type %u\n", (u_int)ELF_R_TYPE(rela->r_info)); return (EFTYPE); } } break; } return (0); #else (void)ef; (void)symaddr; (void)reldata; (void)reltype; (void)relbase; (void)dataaddr; (void)data; (void)len; return (EOPNOTSUPP); #endif }
void relocsym(LSym *s) { Reloc *r; LSym *rs; int32 i, off, siz, fl; vlong o; uchar *cast; ctxt->cursym = s; for(r=s->r; r<s->r+s->nr; r++) { r->done = 1; off = r->off; siz = r->siz; if(off < 0 || off+siz > s->np) { diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np); continue; } if(r->sym != S && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) { diag("%s: not defined", r->sym->name); continue; } if(r->type >= 256) continue; if(r->siz == 0) // informational relocation - no work to do continue; // Solaris needs the ability to reference dynimport symbols. if(HEADTYPE != Hsolaris && r->sym != S && r->sym->type == SDYNIMPORT) diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type); if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable) diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); // Android emulates runtime.tlsg as a regular variable. if (r->type == R_TLS && strcmp(goos, "android") == 0) r->type = R_ADDR; switch(r->type) { default: o = 0; if(archreloc(r, s, &o) < 0) diag("unknown reloc %d", r->type); break; case R_TLS: if(linkmode == LinkInternal && iself && thechar == '5') { // On ELF ARM, the thread pointer is 8 bytes before // the start of the thread-local data block, so add 8 // to the actual TLS offset (r->sym->value). // This 8 seems to be a fundamental constant of // ELF on ARM (or maybe Glibc on ARM); it is not // related to the fact that our own TLS storage happens // to take up 8 bytes. o = 8 + r->sym->value; break; } r->done = 0; o = 0; if(thechar != '6') o = r->add; break; case R_TLS_LE: if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { r->done = 0; r->sym = ctxt->tlsg; r->xsym = ctxt->tlsg; r->xadd = r->add; o = 0; if(thechar != '6') o = r->add; break; } o = ctxt->tlsoffset + r->add; break; case R_TLS_IE: if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { r->done = 0; r->sym = ctxt->tlsg; r->xsym = ctxt->tlsg; r->xadd = r->add; o = 0; if(thechar != '6') o = r->add; break; } if(iself || ctxt->headtype == Hplan9) o = ctxt->tlsoffset + r->add; else if(ctxt->headtype == Hwindows) o = r->add; else sysfatal("unexpected R_TLS_IE relocation for %s", headstr(ctxt->headtype)); break; case R_ADDR: if(linkmode == LinkExternal && r->sym->type != SCONST) { r->done = 0; // set up addend for eventual relocation via outer symbol. rs = r->sym; r->xadd = r->add; while(rs->outer != nil) { r->xadd += symaddr(rs) - symaddr(rs->outer); rs = rs->outer; } if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) diag("missing section for %s", rs->name); r->xsym = rs; o = r->xadd; if(iself) { if(thechar == '6') o = 0; } else if(HEADTYPE == Hdarwin) { if(rs->type != SHOSTOBJ) o += symaddr(rs); } else { diag("unhandled pcrel relocation for %s", headstring); } break; } o = symaddr(r->sym) + r->add; // On amd64, 4-byte offsets will be sign-extended, so it is impossible to // access more than 2GB of static data; fail at link time is better than // fail at runtime. See http://golang.org/issue/7980. // Instead of special casing only amd64, we treat this as an error on all // 64-bit architectures so as to be future-proof. if((int32)o < 0 && PtrSize > 4 && siz == 4) { diag("non-pc-relative relocation address is too big: %#llux", o); errorexit(); } break; case R_CALL: case R_PCREL: // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) { r->done = 0; // set up addend for eventual relocation via outer symbol. rs = r->sym; r->xadd = r->add; while(rs->outer != nil) { r->xadd += symaddr(rs) - symaddr(rs->outer); rs = rs->outer; } r->xadd -= r->siz; // relative to address after the relocated chunk if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) diag("missing section for %s", rs->name); r->xsym = rs; o = r->xadd; if(iself) { if(thechar == '6') o = 0; } else if(HEADTYPE == Hdarwin) { if(r->type == R_CALL) { if(rs->type != SHOSTOBJ) o += symaddr(rs) - rs->sect->vaddr; o -= r->off; // relative to section offset, not symbol } else { o += r->siz; } } else { diag("unhandled pcrel relocation for %s", headstring); } break; } o = 0; if(r->sym) o += symaddr(r->sym); // NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c // compiler. The expression s->value + r->off + r->siz is int32 + int32 + // uchar, and Plan 9 8c incorrectly treats the expression as type uint32 // instead of int32, causing incorrect values when sign extended for adding // to o. The bug only occurs on Plan 9, because this C program is compiled by // the standard host compiler (gcc on most other systems). o += r->add - (s->value + r->off + (int32)r->siz); break; case R_SIZE: o = r->sym->size + r->add; break; } //print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o); switch(siz) { default: ctxt->cursym = s; diag("bad reloc size %#ux for %s", siz, r->sym->name); case 1: // TODO(rsc): Remove. s->p[off] = (int8)o; break; case 4: if(r->type == R_PCREL || r->type == R_CALL) { if(o != (int32)o) diag("pc-relative relocation address is too big: %#llx", o); } else { if(o != (int32)o && o != (uint32)o) diag("non-pc-relative relocation address is too big: %#llux", o); } fl = o; cast = (uchar*)&fl; for(i=0; i<4; i++) s->p[off+i] = cast[inuxi4[i]]; break; case 8: cast = (uchar*)&o; for(i=0; i<8; i++) s->p[off+i] = cast[inuxi8[i]]; break; } } }
// assign addresses void address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; Section *typelink; LSym *sym, *sub; uvlong va; vlong vlen; va = INITTEXT; segtext.rwx = 05; segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { va = rnd(va, s->align); s->vaddr = va; va += s->len; } segtext.len = va - INITTEXT; segtext.filelen = segtext.len; if(HEADTYPE == Hnacl) va += 32; // room for the "halt sled" if(segrodata.sect != nil) { // align to page boundary so as not to mix // rodata and executable text. va = rnd(va, INITRND); segrodata.rwx = 04; segrodata.vaddr = va; segrodata.fileoff = va - segtext.vaddr + segtext.fileoff; segrodata.filelen = 0; for(s=segrodata.sect; s != nil; s=s->next) { va = rnd(va, s->align); s->vaddr = va; va += s->len; } segrodata.len = va - segrodata.vaddr; segrodata.filelen = segrodata.len; } va = rnd(va, INITRND); segdata.rwx = 06; segdata.vaddr = va; segdata.fileoff = va - segtext.vaddr + segtext.fileoff; segdata.filelen = 0; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); if(HEADTYPE == Hplan9) segdata.fileoff = segtext.fileoff + segtext.filelen; data = nil; noptr = nil; bss = nil; noptrbss = nil; for(s=segdata.sect; s != nil; s=s->next) { vlen = s->len; if(s->next) vlen = s->next->vaddr - s->vaddr; s->vaddr = va; va += vlen; segdata.len = va - segdata.vaddr; if(strcmp(s->name, ".data") == 0) data = s; if(strcmp(s->name, ".noptrdata") == 0) noptr = s; if(strcmp(s->name, ".bss") == 0) bss = s; if(strcmp(s->name, ".noptrbss") == 0) noptrbss = s; } segdata.filelen = bss->vaddr - segdata.vaddr; text = segtext.sect; if(segrodata.sect) rodata = segrodata.sect; else rodata = text->next; typelink = rodata->next; symtab = typelink->next; pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { ctxt->cursym = sym; if(sym->sect != nil) sym->value += sym->sect->vaddr; for(sub = sym->sub; sub != nil; sub = sub->sub) sub->value += sym->value; } xdefine("runtime.text", STEXT, text->vaddr); xdefine("runtime.etext", STEXT, text->vaddr + text->len); xdefine("runtime.rodata", SRODATA, rodata->vaddr); xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->len); xdefine("runtime.typelink", SRODATA, typelink->vaddr); xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->len); sym = linklookup(ctxt, "runtime.gcdata", 0); xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size); linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect; sym = linklookup(ctxt, "runtime.gcbss", 0); xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size); linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect; xdefine("runtime.symtab", SRODATA, symtab->vaddr); xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->len); xdefine("runtime.pclntab", SRODATA, pclntab->vaddr); xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->len); xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr); xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); xdefine("runtime.bss", SBSS, bss->vaddr); xdefine("runtime.ebss", SBSS, bss->vaddr + bss->len); xdefine("runtime.data", SDATA, data->vaddr); xdefine("runtime.edata", SDATA, data->vaddr + data->len); xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr); xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); xdefine("runtime.end", SBSS, segdata.vaddr + segdata.len); }