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->extname; 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); }
void doelf(void) { Sym *s, *shstrtab, *dynstr; if(!iself) return; /* predefine strings we need for section headers */ shstrtab = lookup(".shstrtab", 0); shstrtab->type = SELFDATA; shstrtab->reachable = 1; elfstr[ElfStrEmpty] = addstring(shstrtab, ""); elfstr[ElfStrText] = addstring(shstrtab, ".text"); elfstr[ElfStrData] = addstring(shstrtab, ".data"); addstring(shstrtab, ".rodata"); elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); if(!debug['s']) { elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts"); elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab"); elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab"); } elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab"); if(!debug['d']) { /* -d suppresses dynamic loader format */ elfstr[ElfStrInterp] = addstring(shstrtab, ".interp"); elfstr[ElfStrHash] = addstring(shstrtab, ".hash"); elfstr[ElfStrGot] = addstring(shstrtab, ".got"); elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt"); elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic"); elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym"); elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr"); elfstr[ElfStrRel] = addstring(shstrtab, ".rel"); elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt"); elfstr[ElfStrPlt] = addstring(shstrtab, ".plt"); /* interpreter string */ s = lookup(".interp", 0); s->reachable = 1; s->type = SELFDATA; // TODO: rodata /* dynamic symbol table - first entry all zeros */ s = lookup(".dynsym", 0); s->type = SELFDATA; s->reachable = 1; s->value += ELF32SYMSIZE; /* dynamic string table */ s = lookup(".dynstr", 0); s->type = SELFDATA; s->reachable = 1; if(s->size == 0) addstring(s, ""); dynstr = s; /* relocation table */ s = lookup(".rel", 0); s->reachable = 1; s->type = SELFDATA; /* global offset table */ s = lookup(".got", 0); s->reachable = 1; s->type = SELFDATA; /* hash */ s = lookup(".hash", 0); s->reachable = 1; s->type = SELFDATA; /* got.plt */ s = lookup(".got.plt", 0); s->reachable = 1; s->type = SDATA; // writable, so not SELFDATA s = lookup(".plt", 0); s->reachable = 1; s->type = SELFDATA; s = lookup(".rel.plt", 0); s->reachable = 1; s->type = SELFDATA; elfsetupplt(); /* define dynamic elf table */ s = lookup(".dynamic", 0); s->reachable = 1; s->type = SELFDATA; /* * .dynamic table */ elfwritedynentsym(s, DT_HASH, lookup(".hash", 0)); elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0)); elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE); elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); elfwritedynentsym(s, DT_REL, lookup(".rel", 0)); elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0)); elfwritedynent(s, DT_RELENT, ELF32RELSIZE); if(rpath) elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); elfwritedynent(s, DT_PLTREL, DT_REL); elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0)); elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0)); elfwritedynent(s, DT_NULL, 0); } }