static char get_symbol_type(Elf64_Sym *sym, t_elf *nm) { unsigned int i; Elf64_Shdr *sec; char *str; int glob; i = 0; glob = (ELF64_ST_BIND(sym->st_info) == STB_GLOBAL ? 1 : 2); if (strcmp(nm->string_symbol_table + sym->st_name, "data_start") == 0) return ('W'); if (ELF64_ST_BIND(sym->st_info) == STB_WEAK) return (glob == 1 ? 'W' : 'w'); sec = &(*nm).section_header[sym->st_shndx]; str = nm->string_table + sec->sh_name; while (i < SIZE - 1) { if (strncmp(str, g_db[i][0], strlen(g_db[i][0])) == 0) return (g_db[i][glob][0]); ++i; } if (sym->st_shndx == SHN_UNDEF) return (glob == 1 ? 'U' : 'u'); return ('?'); }
void Elf64Output::sort_symtab() { // With ELF, the local symbols must come first in the symbol table. // Annoying, but true. As a result, this function is necessary to // reorder the symbols with the local ones first. std::vector<Elf64_Sym> symtmp; std::vector<size_t> redirect(sym_.size()); // Mapping from old => new position of the symbol in the symbol table. for (int i = 0; i < sym_.size(); ++i) { if (ELF64_ST_BIND(sym_[i].st_info) == STB_LOCAL) { redirect[i] = symtmp.size(); symtmp.push_back(sym_[i]); } } local_syms_ = symtmp.size(); for (int i = 0; i < sym_.size(); ++i) { if (ELF64_ST_BIND(sym_[i].st_info) == STB_GLOBAL) { redirect[i] = symtmp.size(); symtmp.push_back(sym_[i]); } } for (int i = 0; i < text_reloc_.size(); ++i) { Elf64_Word type = ELF64_R_TYPE(text_reloc_[i].r_info); Elf64_Word sym = redirect[ELF64_R_SYM(text_reloc_[i].r_info)]; text_reloc_[i].r_info = ELF64_R_INFO(sym, type); } for (int i = 0; i < data_reloc_.size(); ++i) { Elf64_Word type = ELF64_R_TYPE(data_reloc_[i].r_info); Elf64_Word sym = redirect[ELF64_R_SYM(data_reloc_[i].r_info)]; assert(sym<sym_.size()); data_reloc_[i].r_info = ELF64_R_INFO(sym, type); } sym_ = symtmp; }
int pmelf_getsym64(Elf_Stream s, Elf64_Sym *psym) { if ( 1 != SREAD(psym, sizeof(*psym), 1, s) ) { return -1; } if ( s->needswap ) { #ifdef PMELF_CONFIG_NO_SWAPSUPPORT return -2; #else elf_swap32( &psym->st_name); elf_swap16( &psym->st_shndx); elf_swap64( &psym->st_value); elf_swap64( &psym->st_size); #endif } #ifdef PARANOIA_ON { int x; if ( (x = ELF64_ST_TYPE( psym->st_info )) > STT_MAXSUP ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_getsym - paranoia: unsupported type %i\n", x); return -1; } if ( (x = ELF64_ST_BIND( psym->st_info )) > STB_MAXSUP ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_getsym - paranoia: unsupported binding %i\n", x); return -1; } } #endif return 0; }
static uint_t dt_module_syminit64(dt_module_t *dmp) { const Elf64_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; uint_t i, n = dmp->dm_nsymelems; uint_t asrsv = 0; for (i = 0; i < n; i++, sym++) { const char *name = base + sym->st_name; uchar_t type = ELF64_ST_TYPE(sym->st_info); if (type >= STT_NUM || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) continue; /* skip null or invalid names */ if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) asrsv++; /* reserve space in the address map */ dt_module_symhash_insert(dmp, name, i); } return (asrsv); }
static SYM64 * read_64_syms(Elf64_Sym *data, size_t num, Elf *elf, Elf64_Word link) { #ifdef HAVE_ELF64_GETEHDR SYM64 *s, *buf; size_t i; if( (buf = (SYM64 *)calloc(num, sizeof(SYM64)) ) == NULL) { return NULL; } s = buf; /* save pointer to head of array */ for(i=1; i<num; i++,data++,buf++) { buf->indx = i; buf->name = (char *)elf_strptr(elf, link, data->st_name); buf->value = data->st_value; buf->size = data->st_size; buf->type = ELF64_ST_TYPE(data->st_info); buf->bind = ELF64_ST_BIND(data->st_info); buf->other = data->st_other; buf->shndx = data->st_shndx; } /* end for loop */ return(s); #else return 0; #endif /* HAVE_ELF64_GETEHDR */ }
static int dls_get_external_syms(char *base, struct dls_external_symlist *out) { dls_shdr *s4 = dls_get_shdr_by_name(base, ".dynsym"); dls_shdr *s5 = dls_get_shdr_by_name(base, ".dynstr"); int nr_sym = s4->sh_size / sizeof(dls_sym); int i, count; dls_shdr *first_section = (dls_shdr *)(base + ((dls_ehdr*)base)->e_shoff); char *u = base + s5->sh_offset; dls_sym *sym = (dls_sym *)(base + s4->sh_offset); out->des_array = malloc(sizeof(struct dls_external_sym) * nr_sym); out->des_len = 0; for(i = 0; i < nr_sym; ++i, ++sym) { if(ELF64_ST_BIND(sym->st_info) == 1 && ELF64_ST_TYPE(sym->st_info) == 0) { out->des_array[out->des_len].de_sym = sym; out->des_array[out->des_len].de_name = u + sym->st_name; out->des_array[out->des_len].de_rel = (void*)dls_get_rel_sym(base, s4 - first_section, i); out->des_len++; } } out->des_array = realloc(out->des_array, out->des_len * sizeof(struct dls_external_sym)); return out->des_len; }
char *symbol_binding(unsigned char st_info) { switch (ELF64_ST_BIND(st_info)) { case STB_LOCAL: return "STB_LOCAL"; case STB_GLOBAL: return "STB_GLOBAL"; case STB_WEAK: return "STB_WEAK"; case STB_NUM: return "STB_NUM"; case STB_LOOS: return "STB_LOOS STB_GNU_UNIQUE"; case STB_HIOS: return "STB_HIOS"; case STB_LOPROC: return "STB_LOPROC"; case STB_HIPROC: return "STB_HIPROC"; default: return "unknown"; } }
/* * Sort comparison function for 64-bit symbol address-to-name lookups. We sort * symbols by value. If values are equal, we prefer the symbol that is * non-zero sized, typed, not weak, or lexically first, in that order. */ static int dt_module_symcomp64(const void *lp, const void *rp) { Elf64_Sym *lhs = *((Elf64_Sym **)lp); Elf64_Sym *rhs = *((Elf64_Sym **)rp); if (lhs->st_value != rhs->st_value) return (lhs->st_value > rhs->st_value ? 1 : -1); if ((lhs->st_size == 0) != (rhs->st_size == 0)) return (lhs->st_size == 0 ? 1 : -1); if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) != (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE)) return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) != (ELF64_ST_BIND(rhs->st_info) == STB_WEAK)) return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); return (strcmp(dt_module_strtab + lhs->st_name, dt_module_strtab + rhs->st_name)); }
char get_the_type(int type, int flags, int shndx, int info, int value) { char res; res = 'U'; if (type == SHT_NOBITS && flags == (SHF_WRITE + SHF_ALLOC)) res = 'B'; if ( (type == SHT_PROGBITS || type == SHT_DYNAMIC) && flags == (SHF_WRITE + SHF_ALLOC)) res = 'D'; if (type == SHT_PROGBITS && flags == (SHF_ALLOC + SHF_EXECINSTR)) res = 'T'; if (type == SHT_PROGBITS && flags == SHF_ALLOC) res = 'R'; if (ELF64_ST_BIND(info) == STB_WEAK) res = 'W'; if (type > SHT_DYNSYM) res = 'T'; if ((ELF64_ST_BIND(info) == STB_LOCAL || value == 0) && res != 'U') res += 32; return (res); }
static void get_info_sym(Elf64_Sym *sym) { int info; int bind; int type; int index; char c; info = sym->st_info; bind = ELF64_ST_BIND(info); type = ELF64_ST_TYPE(info); index = sym->st_shndx; c = get_carac(index, type, bind); printf("%c ", c); }
static uint_t dt_module_syminit64(dt_module_t *dmp) { #if STT_NUM != (STT_TLS + 1) #error "STT_NUM has grown. update dt_module_syminit64()" #endif Elf64_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; uint_t i, n = dmp->dm_nsymelems; uint_t asrsv = 0; #if defined(__FreeBSD__) GElf_Ehdr ehdr; int is_elf_obj; gelf_getehdr(dmp->dm_elf, &ehdr); is_elf_obj = (ehdr.e_type == ET_REL); #endif for (i = 0; i < n; i++, sym++) { const char *name = base + sym->st_name; uchar_t type = ELF64_ST_TYPE(sym->st_info); if (type >= STT_NUM || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) continue; /* skip null or invalid names */ if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) { asrsv++; /* reserve space in the address map */ #if defined(__FreeBSD__) sym->st_value += (Elf_Addr) dmp->dm_reloc_offset; if (is_elf_obj && sym->st_shndx != SHN_UNDEF && sym->st_shndx < ehdr.e_shnum) sym->st_value += dmp->dm_sec_offsets[sym->st_shndx]; #endif } dt_module_symhash_insert(dmp, name, i); } return (asrsv); }
static void assign64(void *symp, CexpSym cesp, void *closure) { Elf64_Sym *sp=symp; CexpType t; int s=sp->st_size; cesp->size = s; t=TVoid; switch (ELF64_ST_TYPE(sp->st_info)) { case STT_OBJECT: /* determine the type of variable */ t = cexpTypeGuessFromSize(s); break; case STT_FUNC: t=TFuncP; break; case STT_NOTYPE: t=TVoid; break; case STT_SECTION: t=TVoid; cesp->flags|=CEXP_SYMFLG_SECT; break; default: break; } cesp->value.type = t; switch(ELF64_ST_BIND(sp->st_info)) { case STB_GLOBAL: cesp->flags|=CEXP_SYMFLG_GLBL; break; case STB_WEAK : cesp->flags|=CEXP_SYMFLG_WEAK; break; default: break; } cesp->value.ptv = (CexpVal)(uintptr_t)sp->st_value; }
static const char * filter64(void *ext_sym, void *closure) { Elf64_Sym *sp=ext_sym; char *strtab=closure; if ( STB_LOCAL == ELF64_ST_BIND(sp->st_info) ) return 0; switch (ELF64_ST_TYPE(sp->st_info)) { case STT_OBJECT: case STT_FUNC: case STT_NOTYPE: return strtab + sp->st_name; default: break; } return 0; }
static void dt_module_symsort64(dt_module_t *dmp) { Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data; Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap; const dt_sym_t *dsp = dmp->dm_symchains + 1; uint_t i, n = dmp->dm_symfree; for (i = 1; i < n; i++, dsp++) { Elf64_Sym *sym = symtab + dsp->ds_symid; if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) *sympp++ = sym; } dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap); assert(dmp->dm_aslen <= dmp->dm_asrsv); dt_module_strtab = dmp->dm_strtab.cts_data; qsort(dmp->dm_asmap, dmp->dm_aslen, sizeof (Elf64_Sym *), dt_module_symcomp64); dt_module_strtab = NULL; }
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; }
static int get_global_symbol_address(Context * ctx, ELF_File * file, const char * name, ContextAddress * addr) { unsigned i, j; for (i = 1; i < file->section_cnt; i++) { ELF_Section * sec = file->sections + i; if (sec->size == 0) continue; if (sec->type == SHT_SYMTAB) { ELF_Section * str = NULL; if (sec->link == 0 || sec->link >= file->section_cnt) { errno = EINVAL; return -1; } str = file->sections + sec->link; if (elf_load(sec) < 0) return -1; if (elf_load(str) < 0) return -1; if (file->elf64) { unsigned cnt = (unsigned)(sec->size / sizeof(Elf64_Sym)); for (j = 0; j < cnt; j++) { Elf64_Sym sym = *((Elf64_Sym *)sec->data + j); if (ELF64_ST_BIND(sym.st_info) != STB_GLOBAL) continue; if (file->byte_swap) SWAP(sym.st_name); if (sym_name_cmp((char *)str->data + sym.st_name, name) != 0) continue; switch (ELF64_ST_TYPE(sym.st_info)) { case STT_NOTYPE: /* Check if the NOTYPE symbol is for a section allocated in memory */ if (file->byte_swap) SWAP(sym.st_shndx); if (sym.st_shndx <= 0 || sym.st_shndx >= file->section_cnt || ((file->sections + sym.st_shndx)->flags & SHF_ALLOC) == 0) break; /* fall through */ case STT_OBJECT: case STT_FUNC: if (file->byte_swap) SWAP(sym.st_value); *addr = elf_map_to_run_time_address(ctx, file, NULL, (ContextAddress)sym.st_value); if (errno == 0) return 0; } } } else { unsigned cnt = (unsigned)(sec->size / sizeof(Elf32_Sym)); for (j = 0; j < cnt; j++) { Elf32_Sym sym = *((Elf32_Sym *)sec->data + j); if (ELF32_ST_BIND(sym.st_info) != STB_GLOBAL) continue; if (file->byte_swap) SWAP(sym.st_name); if (sym_name_cmp((char *)str->data + sym.st_name, name) != 0) continue; switch (ELF32_ST_TYPE(sym.st_info)) { case STT_NOTYPE: /* Check if the NOTYPE symbol is for a section allocated in memory */ if (file->byte_swap) SWAP(sym.st_shndx); if (sym.st_shndx <= 0 || sym.st_shndx >= file->section_cnt || ((file->sections + sym.st_shndx)->flags & SHF_ALLOC) == 0) break; /* fall through */ case STT_OBJECT: case STT_FUNC: if (file->byte_swap) SWAP(sym.st_value); *addr = elf_map_to_run_time_address(ctx, file, NULL, (ContextAddress)sym.st_value); if (errno == 0) return 0; } } } } } errno = ENOENT; return -1; }
int main(int argc, char* argv[]) { if(argc < 3) { printf("Usage: smap [kernel elf] [system map]\n"); return 0; } int fd = open(argv[1], O_RDONLY); if(fd < 0) { printf("Cannot open file: %s\n", argv[1]); return 1; } struct stat state; if(stat(argv[1], &state) != 0) { printf("Cannot get state of file: %s\n", argv[1]); return 2; } Elf64_Ehdr* ehdr = mmap(NULL, state.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if(ehdr == (void*)-1) { printf("Cannot open file: %s\n", argv[1]); return 1; } if(ehdr->e_ident[0] != ELFMAG0 || ehdr->e_ident[1] != ELFMAG1 || ehdr->e_ident[2] != ELFMAG2 || ehdr->e_ident[3] != ELFMAG3) { printf("Illegal file format: %s\n", argv[1]); return 3; } Elf64_Shdr* shdr = (Elf64_Shdr*)((uint8_t*)ehdr + ehdr->e_shoff); char* strs = (char*)ehdr + shdr[ehdr->e_shstrndx].sh_offset; Elf64_Shdr* get_shdr(char* name) { for(int i = 0; i < ehdr->e_shnum; i++) { if(strcmp(name, strs + shdr[i].sh_name) == 0) return &shdr[i]; } return NULL; } Elf64_Shdr* strtab = get_shdr(".strtab"); char* str = (char*)ehdr + strtab->sh_offset; char* name(int offset) { return str + offset; } int count = 0; int text_size = 0; Elf64_Shdr* symtab = get_shdr(".symtab"); Elf64_Sym* sym = (void*)ehdr + symtab->sh_offset; int size = symtab->sh_size / sizeof(Elf64_Sym); for(int i = 0; i < size; i++) { if(ELF64_ST_BIND(sym[i].st_info) != STB_GLOBAL) continue; int type = ELF64_ST_TYPE(sym[i].st_info); switch(type) { case STT_NOTYPE: case STT_OBJECT: case STT_FUNC: break; default: printf("Unknown symbol type: %d for %s\n", type, name(sym[i].st_name)); return 4; } count++; text_size += strlen(name(sym[i].st_name)) + 1; } // Make data structure int total = sizeof(Symbol) * (count + 1) + text_size; Symbol* symbols = malloc(total); char* text = (void*)symbols + total - text_size; int j = 0; for(int i = 0; i < size; i++) { if(ELF64_ST_BIND(sym[i].st_info) != STB_GLOBAL) continue; int type = ELF64_ST_TYPE(sym[i].st_info); switch(type) { case STT_NOTYPE: type = SYMBOL_TYPE_NONE; break; case STT_OBJECT: type = SYMBOL_TYPE_DATA; break; case STT_FUNC: type = SYMBOL_TYPE_FUNC; break; default: ;// Not possible } symbols[j].name = (void*)((void*)text - (void*)symbols); symbols[j].type = type; symbols[j].address = (void*)(uint64_t)sym[i].st_value; j++; char* symname = name(sym[i].st_name); int len = strlen(symname) + 1; memcpy(text, symname, len); text += len; } close(fd); // Write int fd2 = open(argv[2], O_RDWR | O_CREAT, 0644); if(fd2 < 0) { printf("Cannot open file: %s\n", argv[2]); return 1; } // Write symbols int len = write(fd2, symbols, total); if(len != total) { printf("Cannot write fully: %d < %d\n", len, total); return 5; } close(fd2); return 0; }
unsigned char Symbol64::getSymbolBinding(){ return ELF64_ST_BIND(entry.st_info); }
struct library_symbol * read_elf(Process *proc) { struct ltelf lte[MAX_LIBRARIES + 1]; size_t i; struct opt_x_t *xptr; struct opt_x_t *opt_x_loc = opt_x; struct library_symbol **lib_tail = NULL; int exit_out = 0; int count = 0; debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename); memset(lte, 0, sizeof(lte)); library_symbols = NULL; library_num = 0; proc->libdl_hooked = 0; if (do_init_elf(lte, proc->filename)) return NULL; memcpy(&main_lte, lte, sizeof(struct ltelf)); if (opt_p && opt_p->pid > 0) { linkmap_init(proc, lte); proc->libdl_hooked = 1; } proc->e_machine = lte->ehdr.e_machine; for (i = 0; i < library_num; ++i) { if (do_init_elf(<e[i + 1], library[i])) error(EXIT_FAILURE, errno, "Can't open \"%s\"", library[i]); } if (!options.no_plt) { #ifdef __mips__ // MIPS doesn't use the PLT and the GOT entries get changed // on startup. proc->need_to_reinitialize_breakpoints = 1; for(i=lte->mips_gotsym; i<lte->dynsym_count;i++){ GElf_Sym sym; const char *name; GElf_Addr addr = arch_plt_sym_val(lte, i, 0); if (gelf_getsym(lte->dynsym, i, &sym) == NULL){ error(EXIT_FAILURE, 0, "Couldn't get relocation from \"%s\"", proc->filename); } name=lte->dynstr+sym.st_name; if(ELF64_ST_TYPE(sym.st_info) != STT_FUNC){ debug(2,"sym %s not a function",name); continue; } add_library_symbol(addr, name, &library_symbols, 0, ELF64_ST_BIND(sym.st_info) != 0); if (!lib_tail) lib_tail = &(library_symbols->next); } #else for (i = 0; i < lte->relplt_count; ++i) { GElf_Rel rel; GElf_Rela rela; GElf_Sym sym; GElf_Addr addr; void *ret; const char *name; if (lte->relplt->d_type == ELF_T_REL) { ret = gelf_getrel(lte->relplt, i, &rel); rela.r_offset = rel.r_offset; rela.r_info = rel.r_info; rela.r_addend = 0; } else ret = gelf_getrela(lte->relplt, i, &rela); if (ret == NULL || ELF64_R_SYM(rela.r_info) >= lte->dynsym_count || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info), &sym) == NULL) error(EXIT_FAILURE, 0, "Couldn't get relocation from \"%s\"", proc->filename); #ifdef PLT_REINITALISATION_BP if (!sym.st_value && PLTs_initialized_by_here) proc->need_to_reinitialize_breakpoints = 1; #endif name = lte->dynstr + sym.st_name; count = library_num ? library_num+1 : 0; if (in_load_libraries(name, lte, count, NULL)) { enum toplt pltt; if (sym.st_value == 0 && lte->plt_stub_vma != 0) { pltt = LS_TOPLT_EXEC; addr = lte->plt_stub_vma + PPC_PLT_STUB_SIZE * i; } else { pltt = PLTS_ARE_EXECUTABLE(lte) ? LS_TOPLT_EXEC : LS_TOPLT_POINT; addr = arch_plt_sym_val(lte, i, &rela); } add_library_symbol(addr, name, &library_symbols, pltt, ELF64_ST_BIND(sym.st_info) == STB_WEAK); if (!lib_tail) lib_tail = &(library_symbols->next); } } #endif // !__mips__ #ifdef PLT_REINITALISATION_BP struct opt_x_t *main_cheat; if (proc->need_to_reinitialize_breakpoints) { /* Add "PLTs_initialized_by_here" to opt_x list, if not already there. */ main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t)); if (main_cheat == NULL) error(EXIT_FAILURE, 0, "Couldn't allocate memory"); main_cheat->next = opt_x_loc; main_cheat->found = 0; main_cheat->name = PLTs_initialized_by_here; for (xptr = opt_x_loc; xptr; xptr = xptr->next) if (strcmp(xptr->name, PLTs_initialized_by_here) == 0 && main_cheat) { free(main_cheat); main_cheat = NULL; break; } if (main_cheat) opt_x_loc = main_cheat; } #endif } else { lib_tail = &library_symbols; } for (i = 0; i < lte->symtab_count; ++i) { GElf_Sym sym; GElf_Addr addr; const char *name; if (gelf_getsym(lte->symtab, i, &sym) == NULL) error(EXIT_FAILURE, 0, "Couldn't get symbol from \"%s\"", proc->filename); name = lte->strtab + sym.st_name; addr = sym.st_value; if (!addr) continue; for (xptr = opt_x_loc; xptr; xptr = xptr->next) if (xptr->name && strcmp(xptr->name, name) == 0) { /* FIXME: Should be able to use &library_symbols as above. But when you do, none of the real library symbols cause breaks. */ add_library_symbol(opd2addr(lte, addr), name, lib_tail, LS_TOPLT_NONE, 0); xptr->found = 1; break; } } unsigned found_count = 0; for (xptr = opt_x_loc; xptr; xptr = xptr->next) { if (xptr->found) continue; GElf_Sym sym; GElf_Addr addr; if (in_load_libraries(xptr->name, lte, library_num+1, &sym)) { debug(2, "found symbol %s @ %#" PRIx64 ", adding it.", xptr->name, sym.st_value); addr = sym.st_value; if (ELF32_ST_TYPE (sym.st_info) == STT_FUNC) { add_library_symbol(addr, xptr->name, lib_tail, LS_TOPLT_NONE, 0); xptr->found = 1; found_count++; } } if (found_count == opt_x_cnt){ debug(2, "done, found everything: %d\n", found_count); break; } } for (xptr = opt_x_loc; xptr; xptr = xptr->next) if ( ! xptr->found) { char *badthing = "WARNING"; #ifdef PLT_REINITALISATION_BP if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) { if (lte->ehdr.e_entry) { add_library_symbol ( opd2addr (lte, lte->ehdr.e_entry), PLTs_initialized_by_here, lib_tail, 1, 0); fprintf (stderr, "WARNING: Using e_ent" "ry from elf header (%p) for " "address of \"%s\"\n", (void*) (long) lte->ehdr.e_entry, PLTs_initialized_by_here); continue; } badthing = "ERROR"; exit_out = 1; } #endif fprintf (stderr, "%s: Couldn't find symbol \"%s\" in file \"%s\" assuming it will be loaded by libdl!" "\n", badthing, xptr->name, proc->filename); } if (exit_out) { exit (1); } for (i = 0; i < library_num + 1; ++i) do_close_elf(<e[i]); return library_symbols; }
int ELFManager::elf_canonicalize_symbol(esymbol **symbol_table, int unsigned type) { int ret; Elf_Shdr shdrs[_ehdr.e_shnum]; ret = elf_read_shdrs(shdrs, _ehdr.e_shnum); if (ret < 0) { return -1; } unsigned int i = 0; for (; i<_ehdr.e_shnum; i++) { if (shdrs[i].sh_type == type) { break; } } if (i == _ehdr.e_shnum) { return -1; } Elf_Shdr *symtab = &shdrs[i]; //读取name Elf_Shdr *link = &shdrs[symtab->sh_link]; char *sym_name = (char *)malloc(link->sh_size); if (sym_name == NULL) { fprintf(stderr, "malloc error!\n"); return -1; } ret = elf_read(link->sh_offset, sym_name, link->sh_size); if (ret < 0) { return -1; } //读取符号表 int count = symtab->sh_size/symtab->sh_entsize; esymbol *esym = (esymbol *)&symbol_table[count]; if(_is_32_bit) { Elf32_Sym syms[count]; ret = elf_read(symtab->sh_offset, syms, symtab->sh_size); if (ret < 0) { return -1; } for (int idx=0; idx<count; idx++) { symbol_table[idx] = &esym[idx]; //printf("name:%s!, symbol_table:%llx\n", &sym_name[syms[idx].st_name], symbol_table[idx]); symbol_table[idx]->name = &sym_name[syms[idx].st_name]; //printf("debug3!\n"); symbol_table[idx]->bind = ELF32_ST_BIND(syms[idx].st_info); symbol_table[idx]->type = ELF32_ST_TYPE(syms[idx].st_info); symbol_table[idx]->shndx = syms[idx].st_shndx; symbol_table[idx]->value = syms[idx].st_value; symbol_table[idx]->size = syms[idx].st_size; } } else { Elf64_Sym syms[count]; ret = elf_read(symtab->sh_offset, syms, symtab->sh_size); if (ret < 0) { return -1; } for (int idx=0; idx<count; idx++) { symbol_table[idx] = &esym[idx]; //printf("name:%s!, symbol_table:%llx\n", &sym_name[syms[idx].st_name], symbol_table[idx]); symbol_table[idx]->name = &sym_name[syms[idx].st_name]; //printf("debug3!\n"); symbol_table[idx]->bind = ELF64_ST_BIND(syms[idx].st_info); symbol_table[idx]->type = ELF64_ST_TYPE(syms[idx].st_info); symbol_table[idx]->shndx = syms[idx].st_shndx; symbol_table[idx]->value = syms[idx].st_value; symbol_table[idx]->size = syms[idx].st_size; } } return count; }
int _dl_md_reloc(elf_object_t *object, int rel, int relsz) { int i; int numrel; int fails = 0; struct load_list *load_list; Elf64_Addr loff; Elf64_Addr ooff; Elf64_Addr got_start, got_end; Elf64_Rel *relocs; const Elf64_Sym *sym, *this; loff = object->obj_base; numrel = object->Dyn.info[relsz] / sizeof(Elf64_Rel); relocs = (Elf64_Rel *)(object->Dyn.info[rel]); if (relocs == NULL) return(0); /* * Change protection of all write protected segments in the * object so we can do relocations in the .rodata section. * After relocation restore protection. */ load_list = object->load_list; while (load_list != NULL) { if ((load_list->prot & PROT_WRITE) == 0) _dl_mprotect(load_list->start, load_list->size, load_list->prot|PROT_WRITE); load_list = load_list->next; } /* XXX We need the got limits to know if reloc is in got. */ /* XXX Relocs against the got should not include the STUB address! */ this = NULL; got_start = 0; got_end = 0; ooff = _dl_find_symbol("__got_start", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) got_start = ooff + this->st_value; this = NULL; ooff = _dl_find_symbol("__got_end", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) got_end = ooff + this->st_value; DL_DEB(("relocating %d\n", numrel)); for (i = 0; i < numrel; i++, relocs++) { Elf64_Addr r_addr = relocs->r_offset + loff; const char *symn; int type; if (ELF64_R_SYM(relocs->r_info) == 0xffffff) continue; ooff = 0; sym = object->dyn.symtab; sym += ELF64_R_SYM(relocs->r_info); symn = object->dyn.strtab + sym->st_name; type = ELF64_R_TYPE(relocs->r_info); this = NULL; if (ELF64_R_SYM(relocs->r_info) && !(ELF64_ST_BIND(sym->st_info) == STB_LOCAL && ELF64_ST_TYPE (sym->st_info) == STT_NOTYPE)) { ooff = _dl_find_symbol(symn, &this, SYM_SEARCH_ALL | SYM_WARNNOTFOUND | SYM_PLT, sym, object, NULL); if (this == NULL) { if (ELF_ST_BIND(sym->st_info) != STB_WEAK) fails++; continue; } } switch (ELF64_R_TYPE(relocs->r_info)) { /* XXX Handle non aligned relocs. .eh_frame * XXX in libstdc++ seems to have them... */ u_int64_t robj; case R_MIPS_REL32_64: if (ELF64_ST_BIND(sym->st_info) == STB_LOCAL && (ELF64_ST_TYPE(sym->st_info) == STT_SECTION || ELF64_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { if ((long)r_addr & 7) { _dl_bcopy((char *)r_addr, &robj, sizeof(robj)); robj += loff + sym->st_value; _dl_bcopy(&robj, (char *)r_addr, sizeof(robj)); } else { *(u_int64_t *)r_addr += loff + sym->st_value; } } else if (this && ((long)r_addr & 7)) { _dl_bcopy((char *)r_addr, &robj, sizeof(robj)); robj += this->st_value + ooff; _dl_bcopy(&robj, (char *)r_addr, sizeof(robj)); } else if (this) { *(u_int64_t *)r_addr += this->st_value + ooff; } break; case R_MIPS_NONE: break; default: _dl_printf("%s: unsupported relocation '%d'\n", _dl_progname, ELF64_R_TYPE(relocs->r_info)); _dl_exit(1); } } DL_DEB(("done %d fails\n", fails)); load_list = object->load_list; while (load_list != NULL) { if ((load_list->prot & PROT_WRITE) == 0) _dl_mprotect(load_list->start, load_list->size, load_list->prot); load_list = load_list->next; } return(fails); }
int perform_relocation(struct elf_module *module, Elf_Rel *rel) { Elf64_Xword *dest = module_get_absolute(rel->r_offset, module); // The symbol reference index Elf64_Word sym = ELF64_R_SYM(rel->r_info); unsigned char type = ELF64_R_TYPE(rel->r_info); // The symbol definition (if applicable) Elf64_Sym *sym_def = NULL; struct elf_module *sym_module = NULL; Elf64_Addr sym_addr = 0x0; if (sym > 0) { // Find out details about the symbol // The symbol reference Elf64_Sym *sym_ref = symbol_get_entry(module, sym); // The symbol definition sym_def = global_find_symbol(module->str_table + sym_ref->st_name, &sym_module); if (sym_def == NULL) { DBG_PRINT("Cannot perform relocation for symbol %s\n", module->str_table + sym_ref->st_name); if (ELF64_ST_BIND(sym_ref->st_info) != STB_WEAK) return -1; // This must be a derivative-specific // function. We're OK as long as we never // execute the function. sym_def = global_find_symbol("undefined_symbol", &sym_module); } // Compute the absolute symbol virtual address sym_addr = (Elf64_Addr)module_get_absolute(sym_def->st_value, sym_module); if (sym_module != module) { // Create a dependency enforce_dependency(sym_module, module); } } switch (type) { case R_X86_64_NONE: // Do nothing break; case R_X86_64_64: *dest += sym_addr; break; case R_X86_64_PC32: *dest += sym_addr - (Elf32_Addr)dest; break; case R_X86_64_COPY: if (sym_addr > 0) { memcpy((void*)dest, (void*)sym_addr, sym_def->st_size); } break; case R_X86_64_GLOB_DAT: case R_X86_64_JUMP_SLOT: //Maybe TODO: Keep track of the GOT entries allocations *dest = sym_addr; break; case R_X86_64_RELATIVE: *dest += module->base_addr; break; default: DBG_PRINT("Relocation type %d not supported\n", type); return -1; } return 0; }