static Elf_Void * arsym(Byte *off, size_t sz, size_t *e, int is64) { char *endstr = (char *)off + sz; register char *str; Byte *endoff; Elf_Void *oas; size_t eltsize = is64 ? 8 : 4; { register size_t n; if (is64) { if (sz < 8 || (sz - 8) / 8 < (n = get8(off))) { _elf_seterr(EFMT_ARSYMSZ, 0); return (0); } } else { if (sz < 4 || (sz - 4) / 4 < (n = get4(off))) { _elf_seterr(EFMT_ARSYMSZ, 0); return (0); } } off += eltsize; endoff = off + n * eltsize; /* * string table must be present, null terminated */ if (((str = (char *)endoff) >= endstr) || (*(endstr - 1) != '\0')) { _elf_seterr(EFMT_ARSYM, 0); return (0); } /* * overflow can occur here, but not likely */ *e = n + 1; n = sizeof (Elf_Arsym) * (n + 1); if ((oas = malloc(n)) == 0) { _elf_seterr(EMEM_ARSYM, errno); return (0); } } { register Elf_Arsym *as = (Elf_Arsym *)oas; while (off < endoff) { if (str >= endstr) { _elf_seterr(EFMT_ARSYMSTR, 0); free(oas); return (0); } if (is64) as->as_off = get8(off); else as->as_off = get4(off); as->as_name = str; as->as_hash = elf_hash(str); ++as; off += eltsize; while (*str++ != '\0') /* LINTED */ ; } as->as_name = 0; as->as_off = 0; as->as_hash = ~(unsigned long)0L; } return (oas); }
int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t) { Elf64_Phdr *dynamic = NULL, *load = NULL; Elf64_Ehdr *ehdr = (void *)mem; Elf64_Dyn *dyn_strtab = NULL; Elf64_Dyn *dyn_symtab = NULL; Elf64_Dyn *dyn_strsz = NULL; Elf64_Dyn *dyn_syment = NULL; Elf64_Dyn *dyn_hash = NULL; Elf64_Word *hash = NULL; Elf64_Phdr *phdr; Elf64_Dyn *d; Elf64_Word *bucket, *chain; Elf64_Word nbucket, nchain; /* * See Elf specification for this magic values. */ static const char elf_ident[] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; char *dynsymbol_names; unsigned int i, j, k; BUILD_BUG_ON(sizeof(elf_ident) != sizeof(ehdr->e_ident)); pr_debug("Parsing at %lx %lx\n", (long)mem, (long)mem + (long)size); /* * Make sure it's a file we support. */ if (builtin_memcmp(ehdr->e_ident, elf_ident, sizeof(elf_ident))) { pr_err("Elf header magic mismatch\n"); return -EINVAL; } /* * We need PT_LOAD and PT_DYNAMIC here. Each once. */ phdr = (void *)&mem[ehdr->e_phoff]; for (i = 0; i < ehdr->e_phnum; i++, phdr++) { if (__ptr_oob(phdr, mem, size)) goto err_oob; switch (phdr->p_type) { case PT_DYNAMIC: if (dynamic) { pr_err("Second PT_DYNAMIC header\n"); return -EINVAL; } dynamic = phdr; break; case PT_LOAD: if (load) { pr_err("Second PT_LOAD header\n"); return -EINVAL; } load = phdr; break; } } if (!load || !dynamic) { pr_err("One of obligated program headers is missed\n"); return -EINVAL; } pr_debug("PT_LOAD p_vaddr: %lx\n", (unsigned long)load->p_vaddr); /* * Dynamic section tags should provide us the rest of information * needed. Note that we're interested in a small set of tags. */ d = (void *)&mem[dynamic->p_offset]; for (i = 0; i < dynamic->p_filesz / sizeof(*d); i++, d++) { if (__ptr_oob(d, mem, size)) goto err_oob; if (d->d_tag == DT_NULL) { break; } else if (d->d_tag == DT_STRTAB) { dyn_strtab = d; pr_debug("DT_STRTAB: %lx\n", (unsigned long)d->d_un.d_ptr); } else if (d->d_tag == DT_SYMTAB) { dyn_symtab = d; pr_debug("DT_SYMTAB: %lx\n", (unsigned long)d->d_un.d_ptr); } else if (d->d_tag == DT_STRSZ) { dyn_strsz = d; pr_debug("DT_STRSZ: %lx\n", (unsigned long)d->d_un.d_val); } else if (d->d_tag == DT_SYMENT) { dyn_syment = d; pr_debug("DT_SYMENT: %lx\n", (unsigned long)d->d_un.d_val); } else if (d->d_tag == DT_HASH) { dyn_hash = d; pr_debug("DT_HASH: %lx\n", (unsigned long)d->d_un.d_ptr); } } if (!dyn_strtab || !dyn_symtab || !dyn_strsz || !dyn_syment || !dyn_hash) { pr_err("Not all dynamic entries are present\n"); return -EINVAL; } dynsymbol_names = &mem[dyn_strtab->d_un.d_val - load->p_vaddr]; if (__ptr_oob(dynsymbol_names, mem, size)) goto err_oob; hash = (void *)&mem[(unsigned long)dyn_hash->d_un.d_ptr - (unsigned long)load->p_vaddr]; if (__ptr_oob(hash, mem, size)) goto err_oob; nbucket = hash[0]; nchain = hash[1]; bucket = &hash[2]; chain = &hash[nbucket + 2]; pr_debug("nbucket %lx nchain %lx bucket %lx chain %lx\n", (long)nbucket, (long)nchain, (unsigned long)bucket, (unsigned long)chain); for (i = 0; i < VDSO_SYMBOL_MAX; i++) { const char * symbol = vdso_symbols[i]; k = elf_hash((const unsigned char *)symbol); for (j = bucket[k % nbucket]; j < nchain && chain[j] != STN_UNDEF; j = chain[j]) { Elf64_Sym *sym = (void *)&mem[dyn_symtab->d_un.d_ptr - load->p_vaddr]; char *name; sym = &sym[j]; if (__ptr_oob(sym, mem, size)) continue; if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC && ELF64_ST_BIND(sym->st_info) != STB_GLOBAL) continue; name = &dynsymbol_names[sym->st_name]; if (__ptr_oob(name, mem, size)) continue; if (builtin_strcmp(name, symbol)) continue; builtin_memcpy(t->symbols[i].name, name, sizeof(t->symbols[i].name)); t->symbols[i].offset = (unsigned long)sym->st_value - load->p_vaddr; break; } } return 0; err_oob: pr_err("Corrupted Elf data\n"); return -EFAULT; }
Elf_Arsym * _libelf_ar_process_symtab(Elf *e, size_t *count) { size_t n, nentries, off; Elf_Arsym *symtab, *sym; unsigned char *p, *s, *end; assert(e != NULL); assert(count != NULL); if (e->e_u.e_ar.e_rawsymtabsz < INTSZ) { LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } p = (unsigned char *) e->e_u.e_ar.e_rawsymtab; end = p + e->e_u.e_ar.e_rawsymtabsz; GET_WORD(p, nentries); p += INTSZ; if (nentries == 0 || p + nentries * INTSZ >= end) { LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } /* Allocate space for a nentries + a sentinel. */ if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries+1))) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } s = p + (nentries * INTSZ); /* start of the string table. */ for (n = nentries, sym = symtab; n > 0; n--) { off = 0; GET_WORD(p, off); sym->as_off = off; sym->as_hash = elf_hash(s); sym->as_name = s; p += INTSZ; sym++; for (; s < end && *s++ != '\0';) /* skip to next string */ ; if (s > end) { LIBELF_SET_ERROR(ARCHIVE, 0); free(symtab); return (NULL); } } /* Fill up the sentinel entry. */ sym->as_name = NULL; sym->as_hash = ~0UL; sym->as_off = (off_t) 0; *count = e->e_u.e_ar.e_symtabsz = nentries + 1; e->e_u.e_ar.e_symtab = symtab; return (symtab); }
Elf * fake_elf32(struct ps_prochandle *P, file_info_t *fptr, uintptr_t addr, Ehdr *ehdr, uint_t phnum, Phdr *phdr) #endif { enum { DI_PLTGOT, DI_JMPREL, DI_PLTRELSZ, DI_PLTREL, DI_SYMTAB, DI_HASH, DI_SYMENT, DI_STRTAB, DI_STRSZ, DI_SUNW_SYMTAB, DI_SUNW_SYMSZ, DI_NENT }; /* * Mask of dynamic options that must be present in a well * formed dynamic section. We need all of these in order to * put together a complete set of elf sections. They are * mandatory in both executables and shared objects so if one * of them is missing, we're in some trouble and should abort. * The PLT items are expected, but we will let them slide if * need be. The DI_SUNW_SYM* items are completely optional, so * we use them if they are present and ignore them otherwise. */ const int di_req_mask = (1 << DI_SYMTAB) | (1 << DI_SYMENT) | (1 << DI_STRTAB) | (1 << DI_STRSZ); int di_mask = 0; size_t size = 0; caddr_t elfdata = NULL; Elf *elf; size_t dynsym_size = 0, ldynsym_size; int dynstr_shndx; Ehdr *ep; Shdr *sp; Dyn *dp = NULL; Dyn *d[DI_NENT] = { 0 }; uint_t i; Off off; size_t pltsz = 0, pltentries = 0; uintptr_t hptr = NULL; Word hnchains = 0, hnbuckets = 0; if (ehdr->e_type == ET_DYN) phdr->p_vaddr += addr; if (P->rap != NULL) { if (rd_get_dyns(P->rap, addr, (void **)&dp, NULL) != RD_OK) goto bad; } else { if ((dp = malloc(phdr->p_filesz)) == NULL) goto bad; if (Pread(P, dp, phdr->p_filesz, phdr->p_vaddr) != phdr->p_filesz) goto bad; } /* * Iterate over the items in the dynamic section, grabbing * the address of items we want and saving them in dp[]. */ for (i = 0; i < phdr->p_filesz / sizeof (Dyn); i++) { switch (dp[i].d_tag) { /* For the .plt section */ case DT_PLTGOT: d[DI_PLTGOT] = &dp[i]; break; case DT_JMPREL: d[DI_JMPREL] = &dp[i]; break; case DT_PLTRELSZ: d[DI_PLTRELSZ] = &dp[i]; break; case DT_PLTREL: d[DI_PLTREL] = &dp[i]; break; /* For the .dynsym section */ case DT_SYMTAB: d[DI_SYMTAB] = &dp[i]; di_mask |= (1 << DI_SYMTAB); break; case DT_HASH: d[DI_HASH] = &dp[i]; di_mask |= (1 << DI_HASH); break; case DT_SYMENT: d[DI_SYMENT] = &dp[i]; di_mask |= (1 << DI_SYMENT); break; case DT_SUNW_SYMTAB: d[DI_SUNW_SYMTAB] = &dp[i]; break; case DT_SUNW_SYMSZ: d[DI_SUNW_SYMSZ] = &dp[i]; break; /* For the .dynstr section */ case DT_STRTAB: d[DI_STRTAB] = &dp[i]; di_mask |= (1 << DI_STRTAB); break; case DT_STRSZ: d[DI_STRSZ] = &dp[i]; di_mask |= (1 << DI_STRSZ); break; } } /* Ensure all required entries were collected */ if ((di_mask & di_req_mask) != di_req_mask) { dprintf("text section missing required dynamic entries: " "required 0x%x, found 0x%x\n", di_req_mask, di_mask); goto bad; } /* SUNW_ldynsym must be adjacent to dynsym. Ignore if not */ if ((d[DI_SUNW_SYMTAB] != NULL) && (d[DI_SUNW_SYMSZ] != NULL) && ((d[DI_SYMTAB]->d_un.d_ptr <= d[DI_SUNW_SYMTAB]->d_un.d_ptr) || (d[DI_SYMTAB]->d_un.d_ptr >= (d[DI_SUNW_SYMTAB]->d_un.d_ptr + d[DI_SUNW_SYMSZ]->d_un.d_val)))) { d[DI_SUNW_SYMTAB] = NULL; d[DI_SUNW_SYMSZ] = NULL; } /* elf header */ size = sizeof (Ehdr); /* program headers from in-core elf fragment */ size += phnum * ehdr->e_phentsize; /* unused shdr, and .shstrtab section */ size += sizeof (Shdr); size += sizeof (Shdr); size += roundup(sizeof (shstr), SH_ADDRALIGN); if (d[DI_HASH] != NULL) { Word hash[2]; hptr = d[DI_HASH]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) hptr += addr; if (Pread(P, hash, sizeof (hash), hptr) != sizeof (hash)) { dprintf("Pread of .hash at %lx failed\n", (long)(hptr)); goto bad; } hnbuckets = hash[0]; hnchains = hash[1]; } /* * .dynsym and .SUNW_ldynsym sections. * * The string table section used for the symbol table and * dynamic sections lies immediately after the dynsym, so the * presence of SUNW_ldynsym changes the dynstr section index. */ if (d[DI_SUNW_SYMTAB] != NULL) { size += sizeof (Shdr); /* SUNW_ldynsym shdr */ ldynsym_size = (size_t)d[DI_SUNW_SYMSZ]->d_un.d_val; dynsym_size = ldynsym_size - (d[DI_SYMTAB]->d_un.d_ptr - d[DI_SUNW_SYMTAB]->d_un.d_ptr); ldynsym_size -= dynsym_size; dynstr_shndx = 4; } else { dynsym_size = sizeof (Sym) * hnchains; ldynsym_size = 0; dynstr_shndx = 3; } size += sizeof (Shdr) + ldynsym_size + dynsym_size; /* .dynstr section */ size += sizeof (Shdr); size += roundup(d[DI_STRSZ]->d_un.d_val, SH_ADDRALIGN); /* .dynamic section */ size += sizeof (Shdr); size += roundup(phdr->p_filesz, SH_ADDRALIGN); /* .plt section */ if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL && d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) { size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val; if (d[DI_PLTREL]->d_un.d_val == DT_RELA) { pltentries = pltrelsz / sizeof (Rela); } else if (d[DI_PLTREL]->d_un.d_val == DT_REL) { pltentries = pltrelsz / sizeof (Rel); } else { /* fall back to the platform default */ #if ((defined(__i386) || defined(__amd64)) && !defined(_ELF64)) pltentries = pltrelsz / sizeof (Rel); dprintf("DI_PLTREL not found, defaulting to Rel"); #else /* (!(__i386 || __amd64)) || _ELF64 */ pltentries = pltrelsz / sizeof (Rela); dprintf("DI_PLTREL not found, defaulting to Rela"); #endif /* (!(__i386 || __amd64) || _ELF64 */ } if (pltentries < PLTREL_MIN_ENTRIES) { dprintf("too few PLT relocation entries " "(found %lu, expected at least %d)\n", (long)pltentries, PLTREL_MIN_ENTRIES); goto bad; } if (pltentries < PLTREL_MIN_ENTRIES + 2) goto done_with_plt; /* * Now that we know the number of plt relocation entries * we can calculate the size of the plt. */ pltsz = (pltentries + M_PLT_XNumber) * M_PLT_ENTSIZE; #if defined(__sparc) /* The sparc PLT always has a (delay slot) nop at the end */ pltsz += 4; #endif /* __sparc */ size += sizeof (Shdr); size += roundup(pltsz, SH_ADDRALIGN); } done_with_plt: if ((elfdata = calloc(1, size)) == NULL) { dprintf("failed to allocate size %ld\n", (long)size); goto bad; } /* LINTED - alignment */ ep = (Ehdr *)elfdata; (void) memcpy(ep, ehdr, offsetof(Ehdr, e_phoff)); ep->e_ehsize = sizeof (Ehdr); ep->e_phoff = sizeof (Ehdr); ep->e_phentsize = ehdr->e_phentsize; ep->e_phnum = phnum; ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize; ep->e_shentsize = sizeof (Shdr); /* * Plt and SUNW_ldynsym sections are optional. C logical * binary operators return a 0 or 1 value, so the following * adds 1 for each optional section present. */ ep->e_shnum = 5 + (pltsz != 0) + (d[DI_SUNW_SYMTAB] != NULL); ep->e_shstrndx = 1; /* LINTED - alignment */ sp = (Shdr *)(elfdata + ep->e_shoff); off = ep->e_shoff + ep->e_shentsize * ep->e_shnum; /* * Copying the program headers directly from the process's * address space is a little suspect, but since we only * use them for their address and size values, this is fine. */ if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize, addr + ehdr->e_phoff) != phnum * ep->e_phentsize) { dprintf("failed to read program headers\n"); goto bad; } /* * The first elf section is always skipped. */ sp++; /* * Section Header: .shstrtab */ sp->sh_name = SHSTR_NDX_shstrtab; sp->sh_type = SHT_STRTAB; sp->sh_flags = SHF_STRINGS; sp->sh_addr = 0; sp->sh_offset = off; sp->sh_size = sizeof (shstr); sp->sh_link = 0; sp->sh_info = 0; sp->sh_addralign = 1; sp->sh_entsize = 0; (void) memcpy(&elfdata[off], shstr, sizeof (shstr)); off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; /* * Section Header: .SUNW_ldynsym */ if (d[DI_SUNW_SYMTAB] != NULL) { sp->sh_name = SHSTR_NDX_SUNW_ldynsym; sp->sh_type = SHT_SUNW_LDYNSYM; sp->sh_flags = SHF_ALLOC; sp->sh_addr = d[DI_SUNW_SYMTAB]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) sp->sh_addr += addr; sp->sh_offset = off; sp->sh_size = ldynsym_size; sp->sh_link = dynstr_shndx; /* Index of 1st global in table that has none == # items */ sp->sh_info = sp->sh_size / sizeof (Sym); sp->sh_addralign = SH_ADDRALIGN; sp->sh_entsize = sizeof (Sym); if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) != sp->sh_size) { dprintf("failed to read .SUNW_ldynsym at %lx\n", (long)sp->sh_addr); goto bad; } off += sp->sh_size; /* No need to round up ldynsym data. Dynsym data is same type */ sp++; } /* * Section Header: .dynsym */ sp->sh_name = SHSTR_NDX_dynsym; sp->sh_type = SHT_DYNSYM; sp->sh_flags = SHF_ALLOC; sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) sp->sh_addr += addr; sp->sh_offset = off; sp->sh_size = dynsym_size; sp->sh_link = dynstr_shndx; sp->sh_info = 1; /* Index of 1st global in table */ sp->sh_addralign = SH_ADDRALIGN; sp->sh_entsize = sizeof (Sym); if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) != sp->sh_size) { dprintf("failed to read .dynsym at %lx\n", (long)sp->sh_addr); goto bad; } off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; /* * Section Header: .dynstr */ sp->sh_name = SHSTR_NDX_dynstr; sp->sh_type = SHT_STRTAB; sp->sh_flags = SHF_ALLOC | SHF_STRINGS; sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) sp->sh_addr += addr; sp->sh_offset = off; sp->sh_size = d[DI_STRSZ]->d_un.d_val; sp->sh_link = 0; sp->sh_info = 0; sp->sh_addralign = 1; sp->sh_entsize = 0; if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) != sp->sh_size) { dprintf("failed to read .dynstr\n"); goto bad; } off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; /* * Section Header: .dynamic */ sp->sh_name = SHSTR_NDX_dynamic; sp->sh_type = SHT_DYNAMIC; sp->sh_flags = SHF_WRITE | SHF_ALLOC; sp->sh_addr = phdr->p_vaddr; if (ehdr->e_type == ET_DYN) sp->sh_addr -= addr; sp->sh_offset = off; sp->sh_size = phdr->p_filesz; sp->sh_link = dynstr_shndx; sp->sh_info = 0; sp->sh_addralign = SH_ADDRALIGN; sp->sh_entsize = sizeof (Dyn); (void) memcpy(&elfdata[off], dp, sp->sh_size); off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; /* * Section Header: .plt */ if (pltsz != 0) { ulong_t plt_symhash; uint_t htmp, ndx; uintptr_t strtabptr, strtabname; Sym sym, *symtabptr; uint_t *hash; char strbuf[sizeof ("_PROCEDURE_LINKAGE_TABLE_")]; /* * Now we need to find the address of the plt by looking * up the "_PROCEDURE_LINKAGE_TABLE_" symbol. */ /* get the address of the symtab and strtab sections */ strtabptr = d[DI_STRTAB]->d_un.d_ptr; symtabptr = (Sym *)(uintptr_t)d[DI_SYMTAB]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) { strtabptr += addr; symtabptr = (Sym*)((uintptr_t)symtabptr + addr); } if ((hptr == NULL) || (hnbuckets == 0) || (hnchains == 0)) { dprintf("empty or missing .hash\n"); goto badplt; } /* find the .hash bucket address for this symbol */ plt_symhash = elf_hash("_PROCEDURE_LINKAGE_TABLE_"); htmp = plt_symhash % hnbuckets; hash = &((uint_t *)hptr)[2 + htmp]; /* read the elf hash bucket index */ if (Pread(P, &ndx, sizeof (ndx), (uintptr_t)hash) != sizeof (ndx)) { dprintf("Pread of .hash at %lx failed\n", (long)hash); goto badplt; } while (ndx) { if (Pread(P, &sym, sizeof (sym), (uintptr_t)&symtabptr[ndx]) != sizeof (sym)) { dprintf("Pread of .symtab at %lx failed\n", (long)&symtabptr[ndx]); goto badplt; } strtabname = strtabptr + sym.st_name; if (Pread_string(P, strbuf, sizeof (strbuf), strtabname) < 0) { dprintf("Pread of .strtab at %lx failed\n", (long)strtabname); goto badplt; } if (strcmp("_PROCEDURE_LINKAGE_TABLE_", strbuf) == 0) break; hash = &((uint_t *)hptr)[2 + hnbuckets + ndx]; if (Pread(P, &ndx, sizeof (ndx), (uintptr_t)hash) != sizeof (ndx)) { dprintf("Pread of .hash at %lx failed\n", (long)hash); goto badplt; } } #if defined(__sparc) if (sym.st_value != d[DI_PLTGOT]->d_un.d_ptr) { dprintf("warning: DI_PLTGOT (%lx) doesn't match " ".plt symbol pointer (%lx)", (long)d[DI_PLTGOT]->d_un.d_ptr, (long)sym.st_value); } #endif /* __sparc */ if (ndx == 0) { dprintf( "Failed to find \"_PROCEDURE_LINKAGE_TABLE_\"\n"); goto badplt; } sp->sh_name = SHSTR_NDX_plt; sp->sh_type = SHT_PROGBITS; sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; sp->sh_addr = sym.st_value; if (ehdr->e_type == ET_DYN) sp->sh_addr += addr; sp->sh_offset = off; sp->sh_size = pltsz; sp->sh_link = 0; sp->sh_info = 0; sp->sh_addralign = SH_ADDRALIGN; sp->sh_entsize = M_PLT_ENTSIZE; if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) != sp->sh_size) { dprintf("failed to read .plt at %lx\n", (long)sp->sh_addr); goto badplt; } off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; } badplt: /* make sure we didn't write past the end of allocated memory */ sp++; assert(((uintptr_t)(sp) - 1) < ((uintptr_t)elfdata + size)); free(dp); if ((elf = elf_memory(elfdata, size)) == NULL) { dprintf("failed to create ELF object " "in memory for size %ld\n", (long)size); free(elfdata); return (NULL); } fptr->file_elfmem = elfdata; return (elf); bad: if (dp != NULL) free(dp); if (elfdata != NULL) free(elfdata); return (NULL); }
Elf_Arsym * _libelf_ar_process_bsd_symtab(Elf *e, size_t *count) { Elf_Arsym *symtab, *sym; unsigned char *end, *p, *p0, *s, *s0; const unsigned int entrysize = 2 * sizeof(long); long arraysize, fileoffset, n, nentries, stroffset, strtabsize; assert(e != NULL); assert(count != NULL); assert(e->e_u.e_ar.e_symtab == NULL); symtab = NULL; /* * The BSD symbol table always contains the count fields even * if there are no entries in it. */ if (e->e_u.e_ar.e_rawsymtabsz < 2 * sizeof(long)) goto symtaberror; p = p0 = (unsigned char *) e->e_u.e_ar.e_rawsymtab; end = p0 + e->e_u.e_ar.e_rawsymtabsz; /* * Retrieve the size of the array of ranlib descriptors and * check it for validity. */ GET_LONG(p, arraysize); if (p0 + arraysize >= end || (arraysize % entrysize != 0)) goto symtaberror; /* * Check the value of the string table size. */ s = p + arraysize; GET_LONG(s, strtabsize); s0 = s; /* Start of string table. */ if (s0 + strtabsize > end) goto symtaberror; nentries = arraysize / entrysize; /* * Allocate space for the returned Elf_Arsym array. */ if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries + 1))) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } /* Read in symbol table entries. */ for (n = 0, sym = symtab; n < nentries; n++, sym++) { GET_LONG(p, stroffset); GET_LONG(p, fileoffset); s = s0 + stroffset; if (s >= end) goto symtaberror; sym->as_off = fileoffset; sym->as_hash = elf_hash((char *) s); sym->as_name = (char *) s; } /* Fill up the sentinel entry. */ sym->as_name = NULL; sym->as_hash = ~0UL; sym->as_off = (off_t) 0; /* Remember the processed symbol table. */ e->e_u.e_ar.e_symtab = symtab; *count = e->e_u.e_ar.e_symtabsz = nentries + 1; return (symtab); symtaberror: if (symtab) free(symtab); LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); }
/* * Prepare an ld_map_ver_t structure for a new mapfile defined version. * * exit: * Returns true for success, false for failure. */ bool ld_map_sym_ver_init(Mapfile *mf, char *name, ld_map_ver_t *mv) { Elf64_Word hash; Ofl_desc *ofl = mf->mf_ofl; mv->mv_name = name; mv->mv_scope = FLG_SCOPE_DFLT; mv->mv_errcnt = 0; /* * If we're generating segments within the image then any symbol * reductions will be processed (ie. applied to relocations and symbol * table entries). Otherwise (when creating a relocatable object) any * versioning information is simply recorded for use in a later * (segment generating) link-edit. */ if (ofl->ofl_flags & FLG_OF_RELOBJ) ofl->ofl_flags |= FLG_OF_VERDEF; /* * If no version descriptors have yet been set up, initialize a base * version to represent the output file itself. This `base' version * catches any internally generated symbols (_end, _etext, etc.) and * serves to initialize the output version descriptor count. */ if (ofl->ofl_vercnt == 0) { if (ld_vers_base(ofl) == (Ver_desc *)S_ERROR) return (false); } /* * If this definition has an associated version name then generate a * new version descriptor and an associated version symbol index table. */ if (name) { ofl->ofl_flags |= FLG_OF_VERDEF; /* * Traverse the present version descriptor list to see if there * is already one of the same name, otherwise create a new one. */ /* LINTED */ hash = (Elf64_Word)elf_hash(name); if (((mv->mv_vdp = ld_vers_find(name, hash, ofl->ofl_verdesc)) == NULL) && ((mv->mv_vdp = ld_vers_desc(name, hash, &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR)) return (false); /* * Initialize any new version with an index, the file from * which it was first referenced, and a WEAK flag (indicates * that there are no symbols assigned to it yet). */ if (mv->mv_vdp->vd_ndx == 0) { /* LINTED */ mv->mv_vdp->vd_ndx = (Elf64_Half)++ofl->ofl_vercnt; mv->mv_vdp->vd_file = ld_map_ifl(mf); mv->mv_vdp->vd_flags = VER_FLG_WEAK; } } else { /* * If a version definition hasn't been specified assign any * symbols to the base version. */ mv->mv_vdp = (Ver_desc *)ofl->ofl_verdesc->apl_data[0]; } return (true); }
Elf_Arsym* elf_getarsym(Elf *elf, size_t *ptr) { Elf_Arsym *syms; size_t count; size_t tmp; size_t i; char *s; char *e; if (!ptr) { ptr = &tmp; } *ptr = 0; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_AR) { seterr(ERROR_NOTARCHIVE); return NULL; } if (elf->e_symtab && !elf->e_free_syms) { if (elf->e_symlen < 4) { seterr(ERROR_SIZE_ARSYMTAB); return NULL; } count = __load_u32M(elf->e_symtab); if (elf->e_symlen < 4 * (count + 1)) { seterr(ERROR_SIZE_ARSYMTAB); return NULL; } if (!(syms = (Elf_Arsym*)malloc((count + 1) * sizeof(*syms)))) { seterr(ERROR_MEM_ARSYMTAB); return NULL; } s = elf->e_symtab + 4 * (count + 1); e = elf->e_symtab + elf->e_symlen; for (i = 0; i < count; i++, s++) { syms[i].as_name = s; while (s < e && *s) { s++; } if (s >= e) { seterr(ERROR_SIZE_ARSYMTAB); free(syms); return NULL; } elf_assert(!*s); syms[i].as_hash = elf_hash(syms[i].as_name); syms[i].as_off = __load_u32M(elf->e_symtab + 4 * (i + 1)); } syms[count].as_name = NULL; syms[count].as_hash = ~0UL; syms[count].as_off = 0; elf->e_symtab = (char*)syms; elf->e_symlen = count + 1; elf->e_free_syms = 1; } *ptr = elf->e_symlen; return (Elf_Arsym*)elf->e_symtab; }
/* * Enter a mapfile defined symbol into the given version * * entry: * mf - Mapfile descriptor * ms - Information related to symbol being added to version * * exit: * On success, returns true. On failure that requires an immediate * halt, returns false. * * On failure that requires eventual halt, but for which it would * be OK to continue parsing in hopes of flushing out additional * problems, increments mv->mv_errcnt, and returns true. */ bool ld_map_sym_enter(Mapfile *mf, ld_map_ver_t *mv, ld_map_sym_t *ms) { Ofl_desc *ofl = mf->mf_ofl; Elf64_Word hash; avl_index_t where; Elf64_Sym *sym; Sym_desc *sdp; const char *conflict; /* * Add the new symbol. It should be noted that all * symbols added by the mapfile start out with global * scope, thus they will fall through the normal symbol * resolution process. Elf64_Symbols defined as locals will * be reduced in scope after all input file processing. */ /* LINTED */ hash = (Elf64_Word)elf_hash(ms->ms_name); //DBG_CALL(Dbg_map_version(ofl->ofl_lml, mv->mv_name, ms->ms_name, // mv->mv_scope)); /* * Make sure that any parent or external declarations fall back to * references. */ if (ms->ms_sdflags & (FLG_SY_PARENT | FLG_SY_EXTERN)) { /* * Turn it into a reference by setting the section index * to UNDEF. */ ms->ms_shndx = SHN_UNDEF; /* * It is wrong to specify size or value for an external symbol. */ if (ms->ms_value_set || (ms->ms_size != 0)) { mf_fatal0(mf, (MSG_MAP_NOEXVLSZ)); mv->mv_errcnt++; return (true); } } if ((sdp = ld_sym_find(ms->ms_name, hash, &where, ofl)) == NULL) { if ((sym = libld_calloc(sizeof (Elf64_Sym), 1)) == NULL) return (false); sym->st_shndx = (Elf64_Half)ms->ms_shndx; sym->st_value = ms->ms_value; sym->st_size = ms->ms_size; sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type); if ((sdp = ld_sym_enter(ms->ms_name, sym, hash, ld_map_ifl(mf), ofl, 0, ms->ms_shndx, ms->ms_sdflags, &where)) == (Sym_desc *)S_ERROR) return (false); sdp->sd_flags &= ~FLG_SY_CLEAN; /* * Identify any references. FLG_SY_MAPREF is * turned off once a relocatable object with * the same symbol is found, thus the existence * of FLG_SY_MAPREF at symbol validation is * used to flag undefined/misspelled entries. */ if (sym->st_shndx == SHN_UNDEF) sdp->sd_flags |= (FLG_SY_MAPREF | FLG_SY_GLOBREF); } else { conflict = NULL; sym = sdp->sd_sym; /* * If this symbol already exists, make sure this * definition doesn't conflict with the former. * Provided it doesn't, multiple definitions * from different mapfiles can augment each * other. */ if (sym->st_value) { if (ms->ms_value && (sym->st_value != ms->ms_value)) conflict = (MSG_MAP_DIFF_SYMVAL); } else { sym->st_value = ms->ms_value; } if (sym->st_size) { if (ms->ms_size && (sym->st_size != ms->ms_size)) conflict = (MSG_MAP_DIFF_SYMSZ); } else { sym->st_size = ms->ms_size; } if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) { if ((ms->ms_type != STT_NOTYPE) && (ELF_ST_TYPE(sym->st_info) != ms->ms_type)) conflict = (MSG_MAP_DIFF_SYMTYP); } else { sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type); } if (sym->st_shndx != SHN_UNDEF) { if ((ms->ms_shndx != SHN_UNDEF) && (sym->st_shndx != ms->ms_shndx)) conflict = (MSG_MAP_DIFF_SYMNDX); } else { sym->st_shndx = sdp->sd_shndx = ms->ms_shndx; } if ((sdp->sd_flags & MSK_SY_GLOBAL) && (sdp->sd_aux->sa_overndx != VER_NDX_GLOBAL) && (mv->mv_vdp->vd_ndx != VER_NDX_GLOBAL) && (sdp->sd_aux->sa_overndx != mv->mv_vdp->vd_ndx)) { conflict = (MSG_MAP_DIFF_SYMVER); } if (conflict) { mf_fatal(mf, (MSG_MAP_SYMDEF1), demangle(ms->ms_name), sdp->sd_file->ifl_name, conflict); mv->mv_errcnt++; return (true); } /* * If this mapfile entry supplies a definition, * indicate that the symbol is now used. */ if (ms->ms_shndx != SHN_UNDEF) sdp->sd_flags |= FLG_SY_MAPUSED; } /* * A symbol declaration that defines a size but no * value is processed as a request to create an * associated backing section. The intent behind this * functionality is to provide OBJT definitions within * filters that are not ABS. ABS symbols don't allow * copy-relocations to be established to filter OBJT * definitions. */ if ((ms->ms_shndx == SHN_ABS) && ms->ms_size && !ms->ms_value_set) { /* Create backing section if not there */ if (sdp->sd_isc == NULL) { Is_desc *isp; if (ms->ms_type == STT_OBJECT) { if ((isp = ld_make_data(ofl, ms->ms_size)) == (Is_desc *)S_ERROR) return (false); } else { if ((isp = ld_make_text(ofl, ms->ms_size)) == (Is_desc *)S_ERROR) return (false); } sdp->sd_isc = isp; isp->is_file = ld_map_ifl(mf); } /* * Now that backing storage has been created, * associate the symbol descriptor. Remove the * symbols special section tag so that it will * be assigned the correct section index as part * of update symbol processing. */ sdp->sd_flags &= ~FLG_SY_SPECSEC; ms->ms_sdflags &= ~FLG_SY_SPECSEC; } /* * Indicate the new symbols scope. Although the * symbols st_other field will eventually be updated as * part of writing out the final symbol, update the * st_other field here to trigger better diagnostics * during symbol validation (for example, undefined * references that are defined symbolic in a mapfile). */ if (mv->mv_scope == FLG_SCOPE_HIDD) { /* * This symbol needs to be reduced to local. */ if (ofl->ofl_flags & FLG_OF_REDLSYM) { sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM); sdp->sd_sym->st_other = STV_ELIMINATE; } else { sdp->sd_flags |= FLG_SY_HIDDEN; sdp->sd_sym->st_other = STV_HIDDEN; } } else if (mv->mv_scope == FLG_SCOPE_ELIM) { /* * This symbol needs to be eliminated. Note, * the symbol is also tagged as local to trigger * any necessary relocation processing prior * to the symbol being eliminated. */ sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM); sdp->sd_sym->st_other = STV_ELIMINATE; } else { /* * This symbol is explicitly defined to remain * global. */ sdp->sd_flags |= ms->ms_sdflags; /* * Qualify any global scope. */ if (mv->mv_scope == FLG_SCOPE_SNGL) { sdp->sd_flags |= (FLG_SY_SINGLE | FLG_SY_NDIR); sdp->sd_sym->st_other = STV_SINGLETON; } else if (mv->mv_scope == FLG_SCOPE_PROT) { sdp->sd_flags |= FLG_SY_PROTECT; sdp->sd_sym->st_other = STV_PROTECTED; } else if (mv->mv_scope == FLG_SCOPE_EXPT) { sdp->sd_flags |= FLG_SY_EXPORT; sdp->sd_sym->st_other = STV_EXPORTED; } else sdp->sd_flags |= FLG_SY_DEFAULT; /* * Record the present version index for later * potential versioning. */ if ((sdp->sd_aux->sa_overndx == 0) || (sdp->sd_aux->sa_overndx == VER_NDX_GLOBAL)) sdp->sd_aux->sa_overndx = mv->mv_vdp->vd_ndx; mv->mv_vdp->vd_flags |= FLG_VER_REFER; } conflict = NULL; /* * Carry out some validity checks to ensure incompatible * symbol characteristics have not been defined. * These checks are carried out after symbols are added * or resolved, to catch single instance, and * multi-instance definition inconsistencies. */ if ((sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_ELIM)) && ((mv->mv_scope != FLG_SCOPE_HIDD) && (mv->mv_scope != FLG_SCOPE_ELIM))) { conflict = (MSG_MAP_DIFF_SYMLCL); } else if ((sdp->sd_flags & (FLG_SY_SINGLE | FLG_SY_EXPORT)) && ((mv->mv_scope != FLG_SCOPE_DFLT) && (mv->mv_scope != FLG_SCOPE_EXPT) && (mv->mv_scope != FLG_SCOPE_SNGL))) { conflict = (MSG_MAP_DIFF_SYMGLOB); } else if ((sdp->sd_flags & FLG_SY_PROTECT) && ((mv->mv_scope != FLG_SCOPE_DFLT) && (mv->mv_scope != FLG_SCOPE_PROT))) { conflict = (MSG_MAP_DIFF_SYMPROT); } else if ((sdp->sd_flags & FLG_SY_NDIR) && (mv->mv_scope == FLG_SCOPE_PROT)) { conflict = (MSG_MAP_DIFF_PROTNDIR); } else if ((sdp->sd_flags & FLG_SY_DIR) && (mv->mv_scope == FLG_SCOPE_SNGL)) { conflict = (MSG_MAP_DIFF_SNGLDIR); } if (conflict) { /* * Select the conflict message from either a * single instance or multi-instance definition. */ if (sdp->sd_file->ifl_name == mf->mf_name) { mf_fatal(mf, (MSG_MAP_SYMDEF2), demangle(ms->ms_name), conflict); } else { mf_fatal(mf, (MSG_MAP_SYMDEF1), demangle(ms->ms_name), sdp->sd_file->ifl_name, conflict); } mv->mv_errcnt++; return (true); } /* * Indicate that this symbol has been explicitly * contributed from a mapfile. */ sdp->sd_flags |= (FLG_SY_MAPFILE | FLG_SY_EXPDEF); /* * If we've encountered a symbol definition simulate * that an input file has been processed - this allows * things like filters to be created purely from a * mapfile. */ if (ms->ms_type != STT_NOTYPE) ofl->ofl_objscnt++; //DBG_CALL(Dbg_map_symbol(ofl, sdp)); /* * If this symbol has an associated filtee, record the * filtee string and associate the string index with the * symbol. This is used later to associate the syminfo * information with the necessary .dynamic entry. */ if (ms->ms_filtee) { Dfltr_desc * dftp; Sfltr_desc sft; size_t idx, _idx, nitems; /* * Make sure we don't duplicate any filtee * strings, and create a new descriptor if * necessary. */ idx = nitems = alist_nitems(ofl->ofl_dtsfltrs); for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, _idx, dftp)) { if ((ms->ms_dft_flag != dftp->dft_flag) || (strcmp(dftp->dft_str, ms->ms_filtee))) continue; idx = _idx; break; } if (idx == nitems) { Dfltr_desc dft; dft.dft_str = ms->ms_filtee; dft.dft_flag = ms->ms_dft_flag; dft.dft_ndx = 0; /* * The following append puts the new * item at the offset contained in * idx, because we know idx contains * the index of the next available slot. */ if (alist_append(&ofl->ofl_dtsfltrs, &dft, sizeof (Dfltr_desc), AL_CNT_OFL_DTSFLTRS) == NULL) return (false); } /* * Create a new filter descriptor for this * symbol. */ sft.sft_sdp = sdp; sft.sft_idx = idx; if (alist_append(&ofl->ofl_symfltrs, &sft, sizeof (Sfltr_desc), AL_CNT_OFL_SYMFLTRS) == NULL) return (false); }
/* * Add a size symbol to a segment * * entry: * mf - Mapfile descriptor * sgp - Segment descriptor * eq_tol - Type of assignment: TK_EQUAL, or TK_PLUSEQ * symname - Name of symbol. Must be in stable static storage * that can be retained. * * exit: * On success, the symbol has been added and true is returned. * Otherwise an error is reported and false is returned. */ bool ld_map_seg_size_symbol(Mapfile *mf, Sg_desc *sgp, Token eq_tok, const char *symname) { Elf64_Sym *sym; /* New symbol pointer */ Sym_desc *sdp; /* New symbol node pointer */ Ifl_desc *ifl; /* Dummy input file structure */ avl_index_t where; Ofl_desc *ofl = mf->mf_ofl; /* * We don't allow resetting the list of size symbols, so if the * operator is TK_EQUAL and the list is not empty, issue an error. * * If we want to lift this restriction, we would have to save the * size symbols and enter them from ld_map_post_process(). Doing that * well would require a significant overhead in saved error reporting * state, and interactions with the same symbols created by symbol * directives. As size symbols are of little practical use, and are * maintained primarily for backward compatibility with SysV, we have * decided not to do that, but to create the symbols as the mapfiles * are processed, and to disallow later attempts to remove them. */ if ((eq_tok == TK_EQUAL) && (aplist_nitems(sgp->sg_sizesym) > 0)) { mf_fatal(mf, (MSG_MAP_SEGSIZE), sgp->sg_name); return (false); } /* * Make sure we have a pseudo file descriptor to associate to the * symbol. */ if ((ifl = ld_map_ifl(mf)) == NULL) return (false); /* * Make sure the symbol doesn't already exist. It is possible that the * symbol has been scoped or versioned, in which case it does exist * but we can freely update it here. */ if ((sdp = ld_sym_find(symname, SYM_NOHASH, &where, ofl)) == NULL) { Elf64_Word hval; if ((sym = libld_calloc(sizeof (Elf64_Sym), 1)) == NULL) return (false); sym->st_shndx = SHN_ABS; sym->st_size = 0; sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT); //DBG_CALL(Dbg_map_size_new(ofl->ofl_lml, symname, // sgp->sg_name, mf->mf_lineno)); /* LINTED */ hval = (Elf64_Word)elf_hash(symname); if ((sdp = ld_sym_enter(symname, sym, hval, ifl, ofl, 0, SHN_ABS, (FLG_SY_SPECSEC | FLG_SY_GLOBREF), &where)) == (Sym_desc *)S_ERROR) return (false); sdp->sd_flags &= ~FLG_SY_CLEAN; //DBG_CALL(Dbg_map_symbol(ofl, sdp)); } else { sym = sdp->sd_sym; if (sym->st_shndx == SHN_UNDEF) { sdp->sd_shndx = sym->st_shndx = SHN_ABS; sdp->sd_flags |= FLG_SY_SPECSEC; sym->st_size = 0; sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT); sdp->sd_flags &= ~FLG_SY_MAPREF; //DBG_CALL(Dbg_map_size_old(ofl, sdp, // sgp->sg_name, mf->mf_lineno)); } else { mf_fatal(mf, (MSG_MAP_SYMDEF1), demangle(sdp->sd_name), sdp->sd_file->ifl_name, (MSG_MAP_DIFF_SYMMUL)); return (false); } } /* * Assign the symbol to the segment. */ if (aplist_append(&sgp->sg_sizesym, sdp, AL_CNT_SG_SIZESYM) == NULL) return (false); return (true); }
static int _elf_nlist(Elf *elf, struct nlist *nl) { unsigned first[PRIME]; Elf_Scn *symtab = NULL; Elf_Scn *strtab = NULL; Elf_Data *symdata; Elf_Data *strdata; size_t symsize; size_t nsymbols; const char *name; struct hash *table; unsigned long hash; unsigned i; struct nlist *np; /* * Get and translate ELF header, section table and so on. * Must be class independent, so don't use elf32_get*(). */ if (elf->e_kind != ELF_K_ELF) { return -1; } if (!elf->e_ehdr && !_elf_cook(elf)) { return -1; } /* * Find symbol table. If there is none, try dynamic symbols. */ for (symtab = elf->e_scn_1; symtab; symtab = symtab->s_link) { if (symtab->s_type == SHT_SYMTAB) { break; } if (symtab->s_type == SHT_DYNSYM) { strtab = symtab; } } if (!symtab && !(symtab = strtab)) { return -1; } /* * Get associated string table. */ i = 0; if (elf->e_class == ELFCLASS32) { i = symtab->s_shdr32.sh_link; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { i = symtab->s_shdr64.sh_link; } #endif /* __LIBELF64 */ if (i == 0) { return -1; } for (strtab = elf->e_scn_1; strtab; strtab = strtab->s_link) { if (strtab->s_index == i) { break; } } if (!strtab || strtab->s_type != SHT_STRTAB) { return -1; } /* * Get and translate section data. */ symdata = elf_getdata(symtab, NULL); strdata = elf_getdata(strtab, NULL); if (!symdata || !strdata) { return -1; } symsize = _msize(elf->e_class, _elf_version, ELF_T_SYM); elf_assert(symsize); nsymbols = symdata->d_size / symsize; if (!symdata->d_buf || !strdata->d_buf || !nsymbols || !strdata->d_size) { return -1; } /* * Build a simple hash table. */ if (!(table = (struct hash*)malloc(nsymbols * sizeof(*table)))) { return -1; } for (i = 0; i < PRIME; i++) { first[i] = 0; } for (i = 0; i < nsymbols; i++) { table[i].name = NULL; table[i].hash = 0; table[i].next = 0; } for (i = 1; i < nsymbols; i++) { name = symbol_name(elf, symdata->d_buf, strdata->d_buf, strdata->d_size, i); if (name == NULL) { free(table); return -1; } if (*name != '\0') { table[i].name = name; table[i].hash = elf_hash((unsigned char *) name); hash = table[i].hash % PRIME; table[i].next = first[hash]; first[hash] = i; } } /* * Lookup symbols, one by one. */ for (np = nl; (name = np->n_name) && *name; np++) { hash = elf_hash((unsigned char *) name); for (i = first[hash % PRIME]; i; i = table[i].next) { if (table[i].hash == hash && !strcmp(table[i].name, name)) { break; } } if (i) { copy_symbol(elf, np, symdata->d_buf, i); } else { np->n_value = 0; np->n_scnum = 0; np->n_type = 0; np->n_sclass = 0; np->n_numaux = 0; } } free(table); return 0; }
h &= ~g; } return h; } static const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n"; int __elfN(lookup_symbol)(struct preloaded_file *fp __unused, elf_file_t ef, const char* name, Elf_Sym *symp) { Elf_Hashelt symnum; Elf_Sym sym; char *strp; unsigned long hash; hash = elf_hash(name); COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum)); while (symnum != STN_UNDEF) { if (symnum >= ef->nchains) { printf(__elfN(bad_symtable)); return ENOENT; } COPYOUT(ef->symtab + symnum, &sym, sizeof(sym)); if (sym.st_name == 0) { printf(__elfN(bad_symtable)); return ENOENT; } strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name));
int main(int argc,char *argv[]) { struct GlobalVars *gv = &gvars; int i,j; char *buf; struct LibPath *libp; struct InputFile *ifn; bool stdlib = TRUE; int so_version = 0; /* minum version for shared objects */ uint16_t flags = 0; /* input file flags */ /* initialize and set default values */ memset(gv,0,sizeof(struct GlobalVars)); initlist(&gv->libpaths); initlist(&gv->rpaths); gv->dynamic = TRUE; /* link with dynamic libraries first */ gv->interp_path = DEFAULT_INTERP_PATH; gv->soname = NULL; gv->endianess = -1; /* endianess is unknown */ /* initialize targets */ for (j=0; fff[j]; j++) { if (fff[j]->init) fff[j]->init(gv); } #ifdef DEFTARGET for (j=0; fff[j]; j++) { if (!strcmp(fff[j]->tname,DEFTARGET)) { gv->dest_format = (uint8_t)j; break; } } if (fff[j] == NULL) { fprintf(stderr,"Configuration warning: Selected default target " "\"%s\" is not included.\nThe current default target " "is \"%s\".\n",DEFTARGET,fff[gv->dest_format]->tname); printf("\n"); } #endif initlist(&gv->inputlist); initlist(&gv->lnksec); gv->dest_name = "a.out"; gv->maxerrors = DEF_MAXERRORS; gv->reloctab_format = RTAB_UNDEF; gv->osec_base_name = NULL; if (argc<2 || (argc==2 && *argv[1]=='?')) { show_usage(); exit(EXIT_SUCCESS); } for (i=1; i<argc; i++) { if (*argv[i] == '-') { /* option detected */ switch (argv[i][1]) { case 'b': if (!strcmp(&argv[i][2],"aseoff")) { /* set base-relative offset */ long bo; sscanf(get_arg(argc,argv,&i),"%li",&bo); fff[gv->dest_format]->baseoff = bo; } else { /* select target format */ if (buf = get_option_arg(argc,argv,&i)) { /* for compatibility with older vlink versions, elf32amiga is automatically converted into elf32powerup and amigaos into amigahunk */ if (!strcmp(buf,"elf32amiga")) buf = "elf32powerup"; else if (!strcmp(buf,"amigaos")) buf = "amigahunk"; for (j=0; fff[j]; j++) { if (!strcmp(fff[j]->tname,buf)) break; } if (fff[j]) gv->dest_format = (uint8_t)j; else error(9,buf); /* invalid target format */ } } break; case 'c': if (!strncmp(&argv[i][2],"lr-",3)) flags &= ~(chk_flags(argv[i])); /* -clr-flags */ else error(2,argv[i]); /* unrecognized option */ break; case 'd': if (!argv[i][2] || argv[i][2]=='c' || argv[i][2]=='p') gv->alloc_common = TRUE; /* force alloc. of common syms. */ else if (argv[i][2] == 'a') gv->alloc_addr = TRUE; /* force alloc. of address syms. */ else error(2,argv[i]); /* unrecognized option */ break; case 'e': if (!strcmp(&argv[i][2],"xport-dynamic")) gv->dyn_exp_all = TRUE; /* export all globals as dynamic */ else /* defines entry point */ gv->entry_name = get_option_arg(argc,argv,&i); break; case 'f': if (!strcmp(&argv[i][2],"ixunnamed")) { gv->fix_unnamed = TRUE; /* assign a name to unnamed sections */ } else { /* set a flavour */ char *name,**fl; if (name = get_option_arg(argc,argv,&i)) { if (fl = gv->flavours.flavours) { char **tmp = alloc((gv->flavours.n_flavours+1)*sizeof(char *)); memcpy(tmp,fl,gv->flavours.n_flavours*sizeof(char *)); free(fl); fl = tmp; } else fl = alloc(sizeof(char *)); fl[gv->flavours.n_flavours++] = name; gv->flavours.flavours = fl; gv->flavours.flavours_len += strlen(name) + 1; } } break; case 'g': if (!strcmp(&argv[i][2],"c-empty")) gv->gc_sects = GCS_EMPTY; else if (!strcmp(&argv[i][2],"c-all")) gv->gc_sects = GCS_ALL; else error(2,argv[i]); /* unrecognized option */ break; case 'h': if (!strcmp(&argv[i][2],"unkattr")) { struct SecAttrOvr *sao; char secname[64]; lword val; val = get_assign_arg(argc,argv,&i,secname,64); sao = addsecattrovr(gv,secname,SAO_MEMFLAGS); sao->memflags = (uint32_t)val; } else { if (argv[i][2] == '\0') { show_usage(); /* help text */ exit(EXIT_SUCCESS); } else error(2,argv[i]); /* unrecognized option */ } break; case 'i': if (!strcmp(&argv[i][2],"nterp")) gv->interp_path = get_arg(argc,argv,&i); else error(2,argv[i]); /* unrecognized option */ break; case 'k': gv->keep_sect_order = TRUE; break; case 'l': /* library specifier */ if (buf = get_option_arg(argc,argv,&i)) { ifn = alloc(sizeof(struct InputFile)); ifn->name = buf; ifn->lib = TRUE; ifn->dynamic = gv->dynamic; ifn->so_ver = so_version; so_version = 0; ifn->flags = flags; addtail(&gv->inputlist,&ifn->n); } break; case 'm': if (!strcmp(&argv[i][2],"inalign")) { long a; sscanf(get_arg(argc,argv,&i),"%li",&a); gv->min_alignment = (uint8_t)a; } else if (!strcmp(&argv[i][2],"rel")) gv->auto_merge = TRUE; else if (!strcmp(&argv[i][2],"type")) gv->merge_same_type = TRUE; else if (!strcmp(&argv[i][2],"ultibase")) gv->multibase = TRUE; else error(2,argv[i]); /* unrecognized option */ break; case 'n': if (!argv[i][2]) gv->no_page_align = TRUE; else if (!strcmp(&argv[i][2],"ostdlib")) stdlib = FALSE; else error(2,argv[i]); /* unrecognized option */ break; case 'o': /* set output file name */ if (!strncmp(&argv[i][2],"sec=",4) && argv[i][6]!='\0') { /* defines a base name of the sections to output */ gv->osec_base_name = &argv[i][6]; gv->output_sections = TRUE; /* output each section as a file */ } else if (!strcmp(&argv[i][2],"sec")) gv->output_sections = TRUE; /* output each section as a file */ else gv->dest_name = get_option_arg(argc,argv,&i); break; case 'q': /* force relocations into final executable */ gv->keep_relocs = TRUE; break; case 'r': /* output is an relocatable object again */ if (!argv[i][2]) { gv->dest_object = TRUE; } else if (!strcmp(&argv[i][2],"path")) { if (buf = get_arg(argc,argv,&i)) { libp = alloc(sizeof(struct LibPath)); libp->path = buf; addtail(&gv->rpaths,&libp->n); } } else error(2,argv[i]); /* unrecognized option */ break; case 's': switch (argv[i][2]) { case '\0': /* strip all symbols */ gv->strip_symbols = STRIP_ALL; break; case 'c': /* -sc force small code */ gv->small_code = TRUE; break; case 'd': /* -d force small data */ gv->small_data = TRUE; break; case 'e': if (!strncmp(&argv[i][3],"t-",2)) /* -set-flags */ flags |= chk_flags(argv[i]); else error(2,argv[i]); /* unrecognized option */ break; case 'h': /* -shared */ if (!strcmp(&argv[i][3],"ared")) gv->dest_sharedobj = TRUE; else error(2,argv[i]); /* unrecognized option */ break; case 'o': /* -soname <real name> */ if (!strcmp(&argv[i][3],"name")) gv->soname = get_arg(argc,argv,&i); else error(2,argv[i]); /* unrecognized option */ break; case 't': /* -static */ if (!strcmp(&argv[i][3],"atic")) gv->dynamic = FALSE; else error(2,argv[i]); /* unrecognized option */ break; default: error(2,argv[i]); /* unrecognized option */ break; } break; case 't': /* trace file accesses */ if (!strcmp(&argv[i][2],"extbaserel")) gv->textbaserel = TRUE; else if (!strncmp(&argv[i][2],"os-",3)) { /* -tos-options for targets ataritos and aoutmint */ if (!strcmp(&argv[i][5],"flags")) { long fl; sscanf(get_arg(argc,argv,&i),"%li",&fl); gv->tosflags = fl; } else if (!strcmp(&argv[i][5],"fastload")) gv->tosflags |= 1; else if (!strcmp(&argv[i][5],"fastram")) gv->tosflags |= 2; else if (!strcmp(&argv[i][5],"fastalloc")) gv->tosflags |= 4; else if (!strcmp(&argv[i][5],"private")) gv->tosflags &= ~0x30; else if (!strcmp(&argv[i][5],"global")) gv->tosflags |= 0x10; else if (!strcmp(&argv[i][5],"super")) gv->tosflags |= 0x20; else if (!strcmp(&argv[i][5],"readable")) gv->tosflags |= 0x30; else if (!strcmp(&argv[i][5],"textbased")) gv->textbasedsyms = 1; else error(2,argv[i]); /* unrecognized option */ } else if (!argv[i][2]) gv->trace_file = stderr; else error(2,argv[i]); /* unrecognized option */ break; case 'u': /* mark symbol as undefined */ if (buf = get_option_arg(argc,argv,&i)) add_symnames(&gv->undef_syms,buf); break; case 'v': /* show version and target info */ show_version(); printf("Standard library path: " #ifdef LIBPATH LIBPATH #endif "\nDefault target: %s\n" "Supported targets:",fff[gv->dest_format]->tname); for (j=0; fff[j]; j++) printf(" %s",fff[j]->tname); printf("\n"); exit(EXIT_SUCCESS); case 'w': /* suppress warnings */ gv->dontwarn = TRUE; break; case 'x': /* discard all local symbols */ gv->discard_local = DISLOC_ALL; break; case 'y': /* trace all accesses on a specific symbol */ if (gv->trace_syms == NULL) gv->trace_syms = alloc_hashtable(TRSYMHTABSIZE); if (buf = get_option_arg(argc,argv,&i)) { struct SymNames **chain = &gv->trace_syms[elf_hash(buf)%TRSYMHTABSIZE]; while (*chain) chain = &(*chain)->next; *chain = alloczero(sizeof(struct SymNames)); (*chain)->name = buf; } break; case 'B': /* set link mode */ if (buf = get_option_arg(argc,argv,&i)) { if (!strcmp(buf,"static")) { gv->dynamic = FALSE; } else if (!strcmp(buf,"dynamic")) { gv->dynamic = TRUE; } else if (!strcmp(buf,"shareable")) { gv->dest_sharedobj = TRUE; } else if (!strcmp(buf,"forcearchive")) { gv->whole_archive = TRUE; } else if (!strcmp(buf,"symbolic")) { ; /* don't know, what this means... */ } else { error(3,buf); /* unknown link mode */ } } break; case 'C': /* select con-/destructor type */ if (buf = get_option_arg(argc,argv,&i)) { if (!strcmp(buf,"gnu")) { gv->collect_ctors_type = CCDT_GNU; } else if (!strcmp(buf,"vbcc")) { gv->collect_ctors_type = CCDT_VBCC; } else if (!strcmp(buf,"vbccelf")) { gv->collect_ctors_type = CCDT_VBCC_ELF; } else if (!strcmp(buf,"sasc")) { gv->collect_ctors_type = CCDT_SASC; } else /* @@@ print error message */ gv->collect_ctors_type = CCDT_NONE; } break; case 'E': /* set endianess */ switch (argv[i][2]) { case 'B': gv->endianess = _BIG_ENDIAN_; break; case 'L': gv->endianess = _LITTLE_ENDIAN_; break; default: error(2,argv[i]); /* unrecognized option */ break; } break; case 'F': /* read a file with object file names */ if (buf = get_option_arg(argc,argv,&i)) ReadListFile(gv,buf,flags); break; case 'L': /* new library search path */ if (buf = get_option_arg(argc,argv,&i)) { libp = alloc(sizeof(struct LibPath)); libp->path = buf; addtail(&gv->libpaths,&libp->n); } break; case 'M': /* mapping output */ gv->map_file = stdout; break; case 'P': /* protect symbol against stripping */ if (buf = get_option_arg(argc,argv,&i)) add_symnames(&gv->prot_syms,buf); break; case 'R': /* use short form for relocations */ if (buf = get_option_arg(argc,argv,&i)) { if (!strcmp(buf,"std")) gv->reloctab_format = RTAB_STANDARD; else if (!strcmp(buf,"add")) gv->reloctab_format = RTAB_ADDEND; else if (!strcmp(buf,"short")) gv->reloctab_format = RTAB_SHORTOFF; else error(123,buf); /* unknown reloc table format ignored */ } break; case 'S': /* strip debugger symbols */ gv->strip_symbols = STRIP_DEBUG; break; case 'T': /* read linker script file or set text address */ if (!strcmp(&argv[i][2],"text")) { if (i+1 < argc) sscanf(argv[++i],"%lli",&gv->start_addr); else error(5,'T'); /* option requires argument */ } else if (buf = get_option_arg(argc,argv,&i)) { if (gv->ldscript = mapfile(buf)) gv->scriptname = buf; else error(8,buf); } break; case 'V': /* set minimum version for next shared object */ if (buf = get_option_arg(argc,argv,&i)) so_version = atoi(buf); break; case 'X': /* discard temporary local symbols only */ gv->discard_local = DISLOC_TMP; break; case 'Z': /* keep trailing zero-bytes at end of section */ gv->keep_trailing_zeros = TRUE; break; default: error(2,argv[i]); /* unrecognized option */ break; } } else { /* normal input file name */ ifn = alloc(sizeof(struct InputFile)); ifn->name = argv[i]; ifn->lib = FALSE; ifn->flags = flags; addtail(&gv->inputlist,&ifn->n); } } /* add default library search path at the end of the list */ if (stdlib) { #ifdef LIBPATH libp = alloc(sizeof(struct LibPath)); libp->path = LIBPATH; /* default search path */ addtail(&gv->libpaths,&libp->n); #endif } /* allocate flavour path buffer and sort flavours */ gv->flavours.flavour_dir = alloc(gv->flavours.flavours_len + 1); if (gv->flavours.n_flavours > 1) { qsort((void *)gv->flavours.flavours, gv->flavours.n_flavours, sizeof(char **), flavours_cmp); } /* link them... */ linker_init(gv); linker_load(gv); /* load all objects and libraries and their symbols */ linker_resolve(gv); /* resolve symbol references */ linker_relrefs(gv); /* find all relative references between sections */ linker_dynprep(gv); /* prepare for dynamic linking */ linker_sectrefs(gv); /* find all referenced sections from the start */ linker_gcsects(gv); /* section garbage collection (gc_sects) */ linker_join(gv); /* join sections with same name and type */ linker_mapfile(gv); /* mapfile output */ linker_copy(gv); /* copy section contents and fix symbol offsets */ linker_delunused(gv);/* delete empty/unused sects. without relocs/symbols */ linker_relocate(gv); /* relocate addresses in joined sections */ linker_write(gv); /* write output file in selected target format */ linker_cleanup(gv); cleanup(gv); return 0; }
void parse_elf_dynamic(Elf32_Ehdr* ehdr, FILE *elf_fp) { Elf32_Shdr *p_shdr = NULL; Elf32_Dyn *p_dyn = NULL; Elf32_Phdr *p_phdr = NULL; int i = 0; uint32_t dynOff = 0, dynSize = 0; uint32_t dyn_symtab_off = 0, dyn_strtab_off = 0, dyn_hash_off = 0; uint32_t dyn_strsz = 0; uint32_t nbucket = 0, nchain = 0; uint32_t *bucket = NULL; uint32_t *chain = NULL; uint32_t str_hash = 0; char* dyn_strtab_buff = NULL; int str_cnt = 0; Elf32_Sym sym_var; uint32_t symbol_index = 0; if(NULL == ehdr || NULL == elf_fp) goto _error; /* 可以通过section和programe来找,但是在运行的时候,需要通过 programe来找,下面通过section来找的代码注释掉了. */ fseek(elf_fp, ehdr->e_phoff, SEEK_SET); p_phdr = (Elf32_Phdr*)malloc(sizeof(Elf32_Phdr) * ehdr->e_phnum); if(NULL == p_phdr) goto _error; if(fread(p_phdr, 1, sizeof(Elf32_Phdr) * ehdr->e_phnum, elf_fp) != sizeof(Elf32_Phdr) * ehdr->e_phnum) { printf("read program header error\n"); goto _error; } for(i = 0; i < ehdr->e_phnum; i++) { if(PT_DYNAMIC == p_phdr[i].p_type) { //这里静态是说p_offset,运行时需要用p_vaddr dynOff = p_phdr[i].p_offset; //运行时用p_p_memsz dynSize = p_phdr[i].p_filesz; } } /* //先解析section的信息,获取.dynamic的偏移和大小 fseek(elf_fp, ehdr->e_shoff, SEEK_SET); p_shdr = (Elf32_Shdr*)malloc(sizeof(Elf32_Shdr) * ehdr->e_shnum); if(NULL == p_shdr) goto _error; if(fread(p_shdr, 1, sizeof(Elf32_Shdr) * ehdr->e_shnum, elf_fp) != sizeof(Elf32_Shdr) * ehdr->e_shnum) { printf("read section header error\n"); goto _error; } for(i = 0; i < ehdr->e_shnum; i++) { if(SHT_DYNAMIC == p_shdr[i].sh_type) { dynOff = p_shdr[i].sh_offset; dynSize = p_shdr[i].sh_size; break; } } */ if(0 == dynOff || 0 == dynSize) { printf("get .dynamic section fail\n"); goto _error; } printf("\n.dynamic 偏移 0x%x, 大小 0x%x\n", dynOff, dynSize); printf("[Nr] %-20s%-12s%-12s\n", "Type", "d_val", "d_ptr"); fseek(elf_fp, dynOff, SEEK_SET); p_dyn = (Elf32_Dyn*)malloc(dynSize); if(NULL == p_dyn) goto _error; if(fread(p_dyn, 1, dynSize, elf_fp) != dynSize) { printf("read .dynamic section error\n"); goto _error; } for(i = 0; i < dynSize /(sizeof(Elf32_Dyn)); i++) { printf("[%02d]", i); if(p_dyn[i].d_tag < 31) { printf(" %-20s", dynamic_type[p_dyn[i].d_tag]); } else { printf(" 0x%-8x ", p_dyn[i].d_tag); } printf("0x%-8x ", p_dyn[i].d_un.d_val); printf("0x%-8x ", p_dyn[i].d_un.d_ptr); switch(p_dyn[i].d_tag) { case DT_HASH: dyn_hash_off = p_dyn[i].d_un.d_ptr; break; case DT_STRTAB: dyn_strtab_off = p_dyn[i].d_un.d_ptr; break; case DT_SYMTAB: dyn_symtab_off = p_dyn[i].d_un.d_ptr; break; case DT_STRSZ: dyn_strsz = p_dyn[i].d_un.d_val; break; default: break; } printf("\n"); } /* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash A hash table of Elf32_Word objects supports symbol table access. The same table layout is used for both the 32-bit and 64-bit file class. Labels appear below to help explain the hash table organization, but they are not part of the specification. nbucket nchain bucket[0] . . . bucket[nbucket-1] chain[0] . . . chain[nchain-1] The bucket array contains nbucket entries, and the chain array contains nchain entries; indexes start at 0. Both bucket and chain hold symbol table indexes. Chain table entries parallel the symbol table. The number of symbol table entries should equal nchain; so symbol table indexes also select chain table entries. A hashing function (shown below) accepts a symbol name and returns a value that may be used to compute a bucket index. Consequently, if the hashing function returns the value x for some name, bucket[x%nbucket] gives an index, y, into both the symbol table and the chain table. If the symbol table entry is not the one desired, chain[y] gives the next symbol table entry with the same hash value. One can follow the chain links until either the selected symbol table entry holds the desired name or the chain entry contains the value STN_UNDEF. unsigned long elf_hash(const unsigned char *name) { unsigned long h = 0, g; while (*name) { h = (h << 4) + *name++; if (g = h & 0xf0000000) h ^= g >> 24; h &= ~g; } return h; } */ printf(" Dynamic Hash Table:\n"); fseek(elf_fp, dyn_hash_off, SEEK_SET); //先把nbucket, nchain读出来. if(fread(&nbucket, 1, 4, elf_fp) != 4) { printf("read hash table nbucket fail\n"); goto _error; } if(fread(&nchain, 1, 4, elf_fp) != 4) { printf("read hash table nchain fail\n"); goto _error; } printf("nbucket 0x%x, nchain 0x%x\n", nbucket, nchain); bucket = (uint32_t*)malloc(nbucket * sizeof(uint32_t)); chain = (uint32_t*)malloc(nchain * sizeof(uint32_t)); if(NULL == bucket || NULL == chain) goto _error; if(fread(bucket, 1, nbucket * sizeof(uint32_t), elf_fp) != nbucket * sizeof(uint32_t)) { printf("read hash table bucket array fail\n"); goto _error; } if(fread(chain, 1, nchain * sizeof(uint32_t), elf_fp) != nchain * sizeof(uint32_t)) { printf("read hash table chain array fail\n"); goto _error; } //通过hashtable把strtable里的字符串算出在symtable的index,然后打印出地址,大小 //先把strtable读出来 dyn_strtab_buff = (char*)malloc(dyn_strsz); if(NULL == dyn_strtab_buff) goto _error; fseek(elf_fp, dyn_strtab_off, SEEK_SET); if(fread(dyn_strtab_buff, 1, dyn_strsz, elf_fp) != dyn_strsz) { printf("read dynstrtab fail\n"); goto _error; } i = 0; while(i < dyn_strsz) { //先通过bucket[x]来获取字符串在symbol中的index,如果不对,那就用chain[bucket[x]] str_hash = elf_hash((unsigned char*)(dyn_strtab_buff + i)); symbol_index = bucket[str_hash % nbucket]; fseek(elf_fp, dyn_symtab_off + symbol_index * sizeof(Elf32_Sym), SEEK_SET); if(fread(&sym_var, 1, sizeof(Elf32_Sym), elf_fp) != sizeof(Elf32_Sym)) { printf("read symbol at index %d fail\n", symbol_index); goto _error; } //bucket[x]不是要找的index,然后用chain[bucket[x]] if(strcmp(dyn_strtab_buff + i, dyn_strtab_buff + sym_var.st_name) != 0) { //循环在chain[]里找,直到找到或者chain[x] = 0; while(1) { symbol_index = chain[symbol_index]; if(symbol_index == 0) break; fseek(elf_fp, dyn_symtab_off + symbol_index * sizeof(Elf32_Sym), SEEK_SET); if(fread(&sym_var, 1, sizeof(Elf32_Sym), elf_fp) != sizeof(Elf32_Sym)) { printf("read symbol at index %d fail, index from chain array\n", symbol_index); goto _error; } if(strcmp(dyn_strtab_buff + i, dyn_strtab_buff + sym_var.st_name) == 0) { printf("Off: 0x%08x, size: 0x%08x %s\n", sym_var.st_value, sym_var.st_size, dyn_strtab_buff + i); break; } } } else { printf("Off: 0x%08x, size: 0x%08x %s\n", sym_var.st_value, sym_var.st_size, dyn_strtab_buff + i); } i += strlen(dyn_strtab_buff + i) + 1; str_cnt++; } printf("str_cnt 0x%x\n", str_cnt); _error: if(p_shdr) free(p_shdr); if(p_dyn) free(p_dyn); if(p_phdr) free(p_phdr); if(bucket) free(bucket); if(chain) free(chain); if(dyn_strtab_buff) free(dyn_strtab_buff); return; }
int in_load_libraries(const char *name, struct ltelf *lte, size_t count, GElf_Sym *sym) { size_t i; unsigned long hash; unsigned long gnu_hash; if (!count) return 1; #ifdef ELF_HASH_TAKES_SIGNED_CHAR hash = elf_hash(name); #else hash = elf_hash((const unsigned char *)name); #endif gnu_hash = private_elf_gnu_hash(name); for (i = 0; i < count; ++i) { if (lte[i].hash == NULL) continue; if (lte[i].hash_type == SHT_GNU_HASH) { Elf32_Word * hashbase = lte[i].hash; Elf32_Word nbuckets = *hashbase++; Elf32_Word symbias = *hashbase++; Elf32_Word bitmask_nwords = *hashbase++; Elf32_Word * buckets; Elf32_Word * chain_zero; Elf32_Word bucket; // +1 for skipped `shift' hashbase += lte[i].ehdr.e_ident[EI_CLASS] * bitmask_nwords + 1; buckets = hashbase; hashbase += nbuckets; chain_zero = hashbase - symbias; bucket = buckets[gnu_hash % nbuckets]; if (bucket != 0) { const Elf32_Word *hasharr = &chain_zero[bucket]; do if ((*hasharr & ~1u) == (gnu_hash & ~1u)) { int symidx = hasharr - chain_zero; if (symbol_matches(lte, i, sym, symidx, name)) return 1; } while ((*hasharr++ & 1u) == 0); } } else { Elf32_Word nbuckets, symndx; Elf32_Word *buckets, *chain; nbuckets = lte[i].hash[0]; buckets = <e[i].hash[2]; chain = <e[i].hash[2 + nbuckets]; for (symndx = buckets[hash % nbuckets]; symndx != STN_UNDEF; symndx = chain[symndx]) if (symbol_matches(lte, i, sym, symndx, name)) return 1; } } return 0; }
elf_sym_t *io_storeLookupSymbol(io_library_t *library, uint32_t symNum, io_library_t **outLib) { elf_sym_t *lookup = library->symtab + symNum; const char *name = library->strtab + lookup->st_name; if(ELF32_ST_BIND(lookup->st_info) == STB_LOCAL) { *outLib = library; return lookup; } else { uint32_t hash = elf_hash(name); elf_sym_t *symbol; // Try to find the symbol in the kernel symbol = io_findKernelSymbol(name); if(symbol) { *outLib = io_kernelLibraryStub(); return symbol; } // Search through the dependencies // Breadth first array_t *dependencyTree = array_create(); array_addObject(dependencyTree, library->dependencies); for(size_t i=0; i<array_count(dependencyTree); i++) { list_t *dependencies = array_objectAtIndex(dependencyTree, i); struct io_dependency_s *dependency = list_first(dependencies); while(dependency) { symbol = io_librarySymbolWithName(dependency->library, name, hash); if(symbol && symbol->st_value != 0x0) { *outLib = dependency->library; array_destroy(dependencyTree); return symbol; } if(list_count(dependency->library->dependencies) > 0) array_addObject(dependencyTree, dependency->library->dependencies); dependency = dependency->next; } } array_destroy(dependencyTree); // Look it up in the library symbol = io_librarySymbolWithName(library, name, hash); if(symbol && symbol->st_value != 0x0) { *outLib = library; return symbol; } } return NULL; }
int link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym) { elf_file_t ef = lf->priv; unsigned long symnum; const Elf_Sym* symp; const char *strp; unsigned long hash; int i; /* If we don't have a hash, bail. */ if (ef->buckets == NULL || ef->nbuckets == 0) { kprintf("link_elf_lookup_symbol: missing symbol hash table\n"); return ENOENT; } /* First, search hashed global symbols */ hash = elf_hash(name); symnum = ef->buckets[hash % ef->nbuckets]; while (symnum != STN_UNDEF) { if (symnum >= ef->nchains) { kprintf("link_elf_lookup_symbol: corrupt symbol table\n"); return ENOENT; } symp = ef->symtab + symnum; if (symp->st_name == 0) { kprintf("link_elf_lookup_symbol: corrupt symbol table\n"); return ENOENT; } strp = ef->strtab + symp->st_name; if (strcmp(name, strp) == 0) { if (symp->st_shndx != SHN_UNDEF || (symp->st_value != 0 && ELF_ST_TYPE(symp->st_info) == STT_FUNC) ) { *sym = (c_linker_sym_t) symp; return 0; } else { return ENOENT; } } symnum = ef->chains[symnum]; } /* If we have not found it, look at the full table (if loaded) */ if (ef->symtab == ef->ddbsymtab) return ENOENT; /* Exhaustive search */ for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { strp = ef->ddbstrtab + symp->st_name; if (strcmp(name, strp) == 0) { if (symp->st_shndx != SHN_UNDEF || (symp->st_value != 0 && ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { *sym = (c_linker_sym_t) symp; return 0; } else { return ENOENT; } } } return ENOENT; }