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); } }
void addstrdata(char *name, char *value) { LSym *s, *sp; char *p; uchar reachable; p = smprint("%s.str", name); sp = linklookup(ctxt, p, 0); free(p); addstring(sp, value); sp->type = SRODATA; s = linklookup(ctxt, name, 0); s->size = 0; s->dupok = 1; reachable = s->reachable; addaddr(ctxt, s, sp); adduint32(ctxt, s, strlen(value)); if(PtrSize == 8) adduint32(ctxt, s, 0); // round struct to pointer width // addstring, addaddr, etc., mark the symbols as reachable. // In this case that is not necessarily true, so stick to what // we know before entering this function. s->reachable = reachable; sp->reachable = reachable; }
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 == Hdarwin) { // 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"); } }
void elfwritedynent(Sym *s, int tag, uint64 val) { if(elf64) { adduint64(s, tag); adduint64(s, val); } else { adduint32(s, tag); adduint32(s, val); } }
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); } }
void elfwritedynentsymsize(LSym *s, int tag, LSym *t) { if(elf64) adduint64(ctxt, s, tag); else adduint32(ctxt, s, tag); addsize(ctxt, s, t); }
void elfwritedynentsymsize(Sym *s, int tag, Sym *t) { if(elf64) adduint64(s, tag); else adduint32(s, tag); addsize(s, t); }
void addstrdata(char *name, char *value) { Sym *s, *sp; char *p; p = smprint("%s.str", name); sp = lookup(p, 0); free(p); addstring(sp, value); s = lookup(name, 0); s->dupok = 1; addaddr(s, sp); adduint32(s, strlen(value)); if(PtrSize == 8) adduint32(s, 0); // round struct to pointer width }
void adddynsym(Link *ctxt, LSym *s) { LSym *d; int t; char *name; if(s->dynid >= 0) return; if(iself) { s->dynid = nelfsym++; d = linklookup(ctxt, ".dynsym", 0); name = s->extname; adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); /* type */ t = STB_GLOBAL << 4; if(s->cgoexport && (s->type&SMASK) == STEXT) t |= STT_FUNC; else t |= STT_OBJECT; adduint8(ctxt, d, t); /* reserved */ adduint8(ctxt, d, 0); /* section where symbol is defined */ if(s->type == SDYNIMPORT) adduint16(ctxt, d, SHN_UNDEF); else adduint16(ctxt, d, 1); /* value */ if(s->type == SDYNIMPORT) adduint64(ctxt, d, 0); else addaddr(ctxt, d, s); /* size of object */ adduint64(ctxt, d, s->size); if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) { elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib)); } } else if(HEADTYPE == Hdarwin) { diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); } else if(HEADTYPE == Hwindows) { // already taken care of } else { diag("adddynsym: unsupported binary format"); } }
void addstrdata(char *name, char *value) { Sym *s, *sp; char *p; p = smprint("%s.str", name); sp = lookup(p, 0); free(p); addstring(sp, value); s = lookup(name, 0); s->size = 0; s->dupok = 1; addaddr(s, sp); adduint32(s, strlen(value)); if(PtrSize == 8) adduint32(s, 0); // round struct to pointer width // in case reachability has already been computed sp->reachable = s->reachable; }
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 == Hdarwin) { adduint32(lookup(".linkedit.got", 0), s->dynid); } else { diag("addgotsym: unsupported binary format"); } }
static void addgotsym(LSym *s) { LSym *got, *rela; if(s->got >= 0) return; adddynsym(ctxt, s); got = linklookup(ctxt, ".got", 0); s->got = got->size; adduint64(ctxt, got, 0); if(iself) { rela = linklookup(ctxt, ".rela", 0); addaddrplus(ctxt, rela, got, s->got); adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); adduint64(ctxt, rela, 0); } else if(HEADTYPE == Hdarwin) { adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); } else { diag("addgotsym: unsupported binary format"); } }
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->type == SDYNIMPORT) 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: r->type = D_PCREL; r->add += 4; if(targ->type == SDYNIMPORT) { addpltsym(targ); r->sym = lookup(".plt", 0); r->add += targ->plt; } return; case 256 + R_386_GOT32: if(targ->type != SDYNIMPORT) { // have symbol // turn MOVL of GOT entry into LEAL of symbol itself if(r->off < 2 || s->p[r->off-2] != 0x8b) { diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); return; } s->p[r->off-2] = 0x8d; r->type = D_GOTOFF; return; } 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->type == SDYNIMPORT) 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->type == SDYNIMPORT) diag("unexpected reloc for dynamic symbol %s", targ->name); return; case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1: if(targ->type == SDYNIMPORT) { addpltsym(targ); r->sym = lookup(".plt", 0); r->add = targ->plt; r->type = D_PCREL; return; } r->type = D_PCREL; return; case 512 + MACHO_FAKE_GOTPCREL: if(targ->type != SDYNIMPORT) { // have symbol // turn MOVL of GOT entry into LEAL of symbol itself if(r->off < 2 || s->p[r->off-2] != 0x8b) { diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); return; } s->p[r->off-2] = 0x8d; r->type = D_PCREL; return; } 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->type != SDYNIMPORT) 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 == Hdarwin && 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); }
void elfdynhash(void) { Sym *s, *sy, *dynstr; int i, j, nbucket, b, nfile; uint32 hc, *chain, *buckets; int nsym; char *name; Elfaux **need; Elflib *needlib; Elflib *l; Elfaux *x; if(!iself) return; nsym = nelfsym; s = lookup(".hash", 0); s->type = SELFROSECT; s->reachable = 1; i = nsym; nbucket = 1; while(i > 0) { ++nbucket; i >>= 1; } needlib = nil; need = malloc(nsym * sizeof need[0]); chain = malloc(nsym * sizeof chain[0]); buckets = malloc(nbucket * sizeof buckets[0]); if(need == nil || chain == nil || buckets == nil) { cursym = nil; diag("out of memory"); errorexit(); } memset(need, 0, nsym * sizeof need[0]); memset(chain, 0, nsym * sizeof chain[0]); memset(buckets, 0, nbucket * sizeof buckets[0]); for(sy=allsym; sy!=S; sy=sy->allsym) { if (sy->dynid <= 0) continue; if(sy->dynimpvers) need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers); name = sy->dynimpname; if(name == nil) name = sy->name; hc = elfhash((uchar*)name); b = hc % nbucket; chain[sy->dynid] = buckets[b]; buckets[b] = sy->dynid; } adduint32(s, nbucket); adduint32(s, nsym); for(i = 0; i<nbucket; i++) adduint32(s, buckets[i]); for(i = 0; i<nsym; i++) adduint32(s, chain[i]); free(chain); free(buckets); // version symbols dynstr = lookup(".dynstr", 0); s = lookup(".gnu.version_r", 0); i = 2; nfile = 0; for(l=needlib; l; l=l->next) { nfile++; // header adduint16(s, 1); // table version j = 0; for(x=l->aux; x; x=x->next) j++; adduint16(s, j); // aux count adduint32(s, addstring(dynstr, l->file)); // file string offset adduint32(s, 16); // offset from header to first aux if(l->next) adduint32(s, 16+j*16); // offset from this header to next else adduint32(s, 0); for(x=l->aux; x; x=x->next) { x->num = i++; // aux struct adduint32(s, elfhash((uchar*)x->vers)); // hash adduint16(s, 0); // flags adduint16(s, x->num); // other - index we refer to this by adduint32(s, addstring(dynstr, x->vers)); // version string offset if(x->next) adduint32(s, 16); // offset from this aux to next else adduint32(s, 0); } } // version references s = lookup(".gnu.version", 0); for(i=0; i<nsym; i++) { if(i == 0) adduint16(s, 0); // first entry - no symbol else if(need[i] == nil) adduint16(s, 1); // global else adduint16(s, need[i]->num); } free(need); s = lookup(".dynamic", 0); elfverneed = nfile; if(elfverneed) { elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0)); elfwritedynent(s, DT_VERNEEDNUM, nfile); elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0)); } elfwritedynent(s, DT_NULL, 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 == Hdarwin) { // 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"); } }
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 != nil && !targ->dynexport) 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: r->type = D_PCREL; r->add += 4; if(targ->dynimpname != nil && !targ->dynexport) { addpltsym(targ); r->sym = lookup(".plt", 0); r->add += targ->plt; } return; case 256 + R_X86_64_GOTPCREL: if(targ->dynimpname == nil || targ->dynexport) { // have symbol if(r->off >= 2 && s->p[r->off-2] == 0x8b) { // turn MOVQ of GOT entry into LEAQ of symbol itself s->p[r->off-2] = 0x8d; r->type = D_PCREL; r->add += 4; return; } // fall back to using GOT and hope for the best (CMOV*) // TODO: just needs relocation, no need to put in .dynsym targ->dynimpname = targ->name; } 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 != nil && !targ->dynexport) 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 != nil && !targ->dynexport) diag("unexpected reloc for dynamic symbol %s", targ->name); return; case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1: if(targ->dynimpname != nil && !targ->dynexport) { 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 != nil && !targ->dynexport) diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name); return; case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: if(targ->dynimpname == nil || targ->dynexport) { // have symbol // turn MOVQ of GOT entry into LEAQ of symbol itself if(r->off < 2 || s->p[r->off-2] != 0x8b) { diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name); return; } s->p[r->off-2] = 0x8d; r->type = D_PCREL; return; } // fall through case 512 + MACHO_X86_64_RELOC_GOT*2 + 1: if(targ->dynimpname == nil || targ->dynexport) diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); 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 || 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); 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 == Hdarwin && 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); }
void adddynsym(Sym *s) { Sym *d, *str; int t; char *name; if(s->dynid >= 0) return; if(s->dynimpname == nil) diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0); 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 == Hdarwin) { // 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 if(HEADTYPE != Hwindows) { diag("adddynsym: unsupported binary format"); } }
void adddynsym(Sym *s) { Sym *d, *str; int t; char *name; if(s->dynid >= 0) return; if(s->dynimpname == nil) diag("adddynsym: no dynamic name for %s", s->name); 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 == Hdarwin) { // 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); if(s->type == SDYNIMPORT) { adduint8(d, 0x01); // type - N_EXT - external symbol adduint8(d, 0); // section } else { adduint8(d, 0x0f); switch(s->type) { default: case STEXT: adduint8(d, 1); break; case SDATA: adduint8(d, 2); break; case SBSS: adduint8(d, 4); break; } } adduint16(d, 0); // desc if(s->type == SDYNIMPORT) adduint64(d, 0); // value else addaddr(d, s); } else if(HEADTYPE != Hwindows) { diag("adddynsym: unsupported binary format"); } }
void adddynsym(Sym *s) { Sym *d; int t; char *name; if(s->dynid >= 0) return; if(iself) { s->dynid = nelfsym++; d = lookup(".dynsym", 0); /* name */ name = s->extname; 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->cgoexport && (s->type&SMASK) == STEXT) t |= STT_FUNC; else t |= STT_OBJECT; adduint8(d, t); adduint8(d, 0); /* shndx */ if(s->type == SDYNIMPORT) 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 == Hdarwin) { diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); } else if(HEADTYPE == Hwindows) { // already taken care of } else { diag("adddynsym: unsupported binary format"); } }
void ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) { int32 ipc; Prog *p; Sym *h[NSYM], *s; int v, o, r, skip; uint32 sig; char *name; int ntext; int32 eof; char src[1024], *x; Prog *lastp; lastp = nil; ntext = 0; eof = Boffset(f) + len; src[0] = 0; newloop: memset(h, 0, sizeof(h)); version++; histfrogp = 0; ipc = pc; skip = 0; loop: if(f->state == Bracteof || Boffset(f) >= eof) goto eof; o = BGETC(f); if(o == Beof) goto eof; if(o <= AXXX || o >= ALAST) { diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); print(" probably not a .5 file\n"); errorexit(); } if(o == ANAME || o == ASIGNAME) { sig = 0; if(o == ASIGNAME) sig = Bget4(f); v = BGETC(f); /* type */ o = BGETC(f); /* sym */ r = 0; if(v == D_STATIC) r = version; name = Brdline(f, '\0'); if(name == nil) { if(Blinelen(f) > 0) { fprint(2, "%s: name too long\n", pn); errorexit(); } goto eof; } x = expandpkg(name, pkg); s = lookup(x, r); if(x != name) free(x); if(sig != 0){ if(s->sig != 0 && s->sig != sig) diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name); s->sig = sig; s->file = pn; } if(debug['W']) print(" ANAME %s\n", s->name); if(o < 0 || o >= nelem(h)) { fprint(2, "%s: mangled input file\n", pn); errorexit(); } h[o] = s; if((v == D_EXTERN || v == D_STATIC) && s->type == 0) s->type = SXREF; if(v == D_FILE) { if(s->type != SFILE) { histgen++; s->type = SFILE; s->value = histgen; } if(histfrogp < MAXHIST) { histfrog[histfrogp] = s; histfrogp++; } else collapsefrog(s); } goto loop; } p = mal(sizeof(Prog)); p->as = o; p->scond = BGETC(f); p->reg = BGETC(f); p->line = Bget4(f); zaddr(f, &p->from, h); zaddr(f, &p->to, h); if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG) diag("register out of range %A %d", p->as, p->reg); p->link = P; p->cond = P; if(debug['W']) print("%P\n", p); switch(o) { case AHISTORY: if(p->to.offset == -1) { addlib(src, pn); histfrogp = 0; goto loop; } if(src[0] == '\0') copyhistfrog(src, sizeof src); addhist(p->line, D_FILE); /* 'z' */ if(p->to.offset) addhist(p->to.offset, D_FILE1); /* 'Z' */ histfrogp = 0; goto loop; case AEND: histtoauto(); if(cursym != nil && cursym->text) cursym->autom = curauto; curauto = 0; cursym = nil; if(Boffset(f) == eof) return; goto newloop; case AGLOBL: s = p->from.sym; if(s == S) { diag("GLOBL must have a name\n%P", p); errorexit(); } if(s->type == 0 || s->type == SXREF) { s->type = SBSS; s->value = 0; } if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { diag("redefinition: %s\n%P", s->name, p); s->type = SBSS; s->value = 0; } if(p->to.offset > s->size) s->size = p->to.offset; if(p->reg & DUPOK) s->dupok = 1; if(p->reg & RODATA) s->type = SRODATA; else if(p->reg & NOPTR) s->type = SNOPTRBSS; break; case ADATA: // Assume that AGLOBL comes after ADATA. // If we've seen an AGLOBL that said this sym was DUPOK, // ignore any more ADATA we see, which must be // redefinitions. s = p->from.sym; if(s->dupok) { // if(debug['v']) // Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); goto loop; } if(s->file == nil) s->file = pn; else if(s->file != pn) { diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); errorexit(); } savedata(s, p, pn); unmal(p, sizeof *p); break; case AGOK: diag("unknown opcode\n%P", p); p->pc = pc; pc++; break; case ATEXT: if(cursym != nil && cursym->text) { histtoauto(); cursym->autom = curauto; curauto = 0; } s = p->from.sym; if(s == S) { diag("TEXT must have a name\n%P", p); errorexit(); } cursym = s; if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) { skip = 1; goto casedef; } if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { /* redefinition, so file has probably been seen before */ if(debug['v']) Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name); return; } skip = 0; if(s->type != 0 && s->type != SXREF) diag("redefinition: %s\n%P", s->name, p); if(etextp) etextp->next = s; else textp = s; etextp = s; p->align = 4; autosize = (p->to.offset+3L) & ~3L; p->to.offset = autosize; autosize += 4; s->type = STEXT; s->text = p; s->value = pc; lastp = p; p->pc = pc; pc++; break; case ASUB: if(p->from.type == D_CONST) if(p->from.name == D_NONE) if(p->from.offset < 0) { p->from.offset = -p->from.offset; p->as = AADD; } goto casedef; case AADD: if(p->from.type == D_CONST) if(p->from.name == D_NONE) if(p->from.offset < 0) { p->from.offset = -p->from.offset; p->as = ASUB; } goto casedef; case AMOVWD: case AMOVWF: case AMOVDW: case AMOVFW: case AMOVFD: case AMOVDF: // case AMOVF: // case AMOVD: case ACMPF: case ACMPD: case AADDF: case AADDD: case ASUBF: case ASUBD: case AMULF: case AMULD: case ADIVF: case ADIVD: goto casedef; case AMOVF: if(skip) goto casedef; if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 && (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { /* size sb 9 max */ sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { s->type = SBSS; adduint32(s, ieeedtof(&p->from.ieee)); s->reachable = 0; } p->from.type = D_OREG; p->from.sym = s; p->from.name = D_EXTERN; p->from.offset = 0; } goto casedef; case AMOVD: if(skip) goto casedef; if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 && (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { /* size sb 18 max */ sprint(literal, "$%ux.%ux", p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { s->type = SBSS; adduint32(s, p->from.ieee.l); adduint32(s, p->from.ieee.h); s->reachable = 0; } p->from.type = D_OREG; p->from.sym = s; p->from.name = D_EXTERN; p->from.offset = 0; } goto casedef; default: casedef: if(skip) nopout(p); p->pc = pc; pc++; if(p->to.type == D_BRANCH) p->to.offset += ipc; if(lastp == nil) { if(p->as != ANOP) diag("unexpected instruction: %P", p); break; } lastp->link = p; lastp = p; break; } goto loop; eof: diag("truncated object file: %s", pn); }
void ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) { int32 ipc; Prog *p; int v, o, r, skip; Sym *h[NSYM], *s; uint32 sig; int ntext; int32 eof; char *name, *x; char src[1024]; Prog *lastp; lastp = nil; ntext = 0; eof = Boffset(f) + len; src[0] = 0; newloop: memset(h, 0, sizeof(h)); version++; histfrogp = 0; ipc = pc; skip = 0; loop: if(f->state == Bracteof || Boffset(f) >= eof) goto eof; o = Bgetc(f); if(o == Beof) goto eof; o |= Bgetc(f) << 8; if(o <= AXXX || o >= ALAST) { if(o < 0) goto eof; diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); print(" probably not a .%c file\n", thechar); errorexit(); } if(o == ANAME || o == ASIGNAME) { sig = 0; if(o == ASIGNAME) sig = Bget4(f); v = Bgetc(f); /* type */ o = Bgetc(f); /* sym */ r = 0; if(v == D_STATIC) r = version; name = Brdline(f, '\0'); if(name == nil) { if(Blinelen(f) > 0) { fprint(2, "%s: name too long\n", pn); errorexit(); } goto eof; } x = expandpkg(name, pkg); s = lookup(x, r); if(x != name) free(x); if(debug['S'] && r == 0) sig = 1729; if(sig != 0){ if(s->sig != 0 && s->sig != sig) diag("incompatible type signatures" "%ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name); s->sig = sig; s->file = pn; } if(debug['W']) print(" ANAME %s\n", s->name); if(o < 0 || o >= nelem(h)) mangle(pn); h[o] = s; if((v == D_EXTERN || v == D_STATIC) && s->type == 0) s->type = SXREF; if(v == D_FILE) { if(s->type != SFILE) { histgen++; s->type = SFILE; s->value = histgen; } if(histfrogp < MAXHIST) { histfrog[histfrogp] = s; histfrogp++; } else collapsefrog(s); dwarfaddfrag(s->value, s->name); } goto loop; } p = mal(sizeof(*p)); p->as = o; p->line = Bget4(f); p->back = 2; p->ft = 0; p->tt = 0; zaddr(pn, f, &p->from, h); fromgotype = adrgotype; zaddr(pn, f, &p->to, h); if(debug['W']) print("%P\n", p); switch(p->as) { case AHISTORY: if(p->to.offset == -1) { addlib(src, pn); histfrogp = 0; goto loop; } if(src[0] == '\0') copyhistfrog(src, sizeof src); addhist(p->line, D_FILE); /* 'z' */ if(p->to.offset) addhist(p->to.offset, D_FILE1); /* 'Z' */ histfrogp = 0; goto loop; case AEND: histtoauto(); if(cursym != nil && cursym->text) cursym->autom = curauto; curauto = 0; cursym = nil; if(Boffset(f) == eof) return; goto newloop; case AGLOBL: s = p->from.sym; if(s->type == 0 || s->type == SXREF) { s->type = SBSS; s->size = 0; } if(s->type != SBSS && !s->dupok) { diag("%s: redefinition: %s in %s", pn, s->name, TNAME); s->type = SBSS; s->size = 0; } if(p->to.offset > s->size) s->size = p->to.offset; if(p->from.scale & DUPOK) s->dupok = 1; if(p->from.scale & RODATA) s->type = SRODATA; goto loop; case ADATA: // Assume that AGLOBL comes after ADATA. // If we've seen an AGLOBL that said this sym was DUPOK, // ignore any more ADATA we see, which must be // redefinitions. s = p->from.sym; if(s->dupok) { // if(debug['v']) // Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); goto loop; } if(s->file == nil) s->file = pn; else if(s->file != pn) { diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); errorexit(); } savedata(s, p, pn); unmal(p, sizeof *p); goto loop; case AGOK: diag("%s: GOK opcode in %s", pn, TNAME); pc++; goto loop; case ATEXT: s = p->from.sym; if(s->text != nil) { diag("%s: %s: redefinition", pn, s->name); return; } if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { /* redefinition, so file has probably been seen before */ if(debug['v']) diag("skipping: %s: redefinition: %s", pn, s->name); return; } if(cursym != nil && cursym->text) { histtoauto(); cursym->autom = curauto; curauto = 0; } skip = 0; if(etextp) etextp->next = s; else textp = s; etextp = s; s->text = p; cursym = s; if(s->type != 0 && s->type != SXREF) { if(p->from.scale & DUPOK) { skip = 1; goto casdef; } diag("%s: redefinition: %s\n%P", pn, s->name, p); } s->type = STEXT; s->value = pc; lastp = p; p->pc = pc++; goto loop; case AFMOVF: case AFADDF: case AFSUBF: case AFSUBRF: case AFMULF: case AFDIVF: case AFDIVRF: case AFCOMF: case AFCOMFP: if(skip) goto casdef; if(p->from.type == D_FCONST) { /* size sb 9 max */ sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { s->type = SDATA; adduint32(s, ieeedtof(&p->from.ieee)); s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; p->from.offset = 0; } goto casdef; case AFMOVD: case AFADDD: case AFSUBD: case AFSUBRD: case AFMULD: case AFDIVD: case AFDIVRD: case AFCOMD: case AFCOMDP: if(skip) goto casdef; if(p->from.type == D_FCONST) { /* size sb 18 max */ sprint(literal, "$%ux.%ux", p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { s->type = SDATA; adduint32(s, p->from.ieee.l); adduint32(s, p->from.ieee.h); s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; p->from.offset = 0; } goto casdef; casdef: default: if(skip) nopout(p); p->pc = pc; pc++; if(p->to.type == D_BRANCH) p->to.offset += ipc; if(lastp == nil) { if(p->as != ANOP) diag("unexpected instruction: %P", p); goto loop; } lastp->link = p; lastp = p; goto loop; } eof: diag("truncated object file: %s", pn); }
void adddynsym(Sym *s) { Sym *d, *str; int t; char *name; vlong off; if(s->dynid >= 0) return; if(s->dynimpname == nil) 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&SMASK) == 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 == Hdarwin) { // Mach-O symbol nlist32 d = lookup(".dynsym", 0); name = s->dynimpname; if(name == nil) name = s->name; if(d->size == 0 && ndynexp > 0) { // pre-allocate for dynexps symgrow(d, ndynexp*12); } if(s->dynid <= -100) { // pre-allocated, see cmd/ld/go.c:^sortdynexp() s->dynid = -s->dynid-100; off = s->dynid*12; } else { off = d->size; s->dynid = off/12; } // darwin still puts _ prefixes on all C symbols str = lookup(".dynstr", 0); setuint32(d, off, str->size); off += 4; adduint8(str, '_'); addstring(str, name); if(s->type == SDYNIMPORT) { setuint8(d, off, 0x01); // type - N_EXT - external symbol off++; setuint8(d, off, 0); // section off++; } else { setuint8(d, off, 0x0f); off++; switch(s->type) { default: case STEXT: setuint8(d, off, 1); break; case SDATA: setuint8(d, off, 2); break; case SBSS: setuint8(d, off, 4); break; } off++; } setuint16(d, off, 0); // desc off += 2; if(s->type == SDYNIMPORT) setuint32(d, off, 0); // value else setaddr(d, off, s); off += 4; } else if(HEADTYPE != Hwindows) { diag("adddynsym: unsupported binary format"); } }