Пример #1
0
static void compute_unresolved_hash(struct elf_info *elf)
{

	Elf_Sym *sym;
	ksym_hash_t *hash_values = elf->undef_hash.start;

	if (!hash_values)
		/* .undef.hash section is not present */
		return;

	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
		if (sym->st_shndx == SHN_UNDEF) {
			/* undefined symbol */
			if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
			    ELF_ST_BIND(sym->st_info) != STB_WEAK)
				continue;
			else {
				/* GLOBAL or WEAK undefined symbols */
				*hash_values = gnu_hash((unsigned char *)
						(elf->strtab + sym->st_name));
				/*
				 * The hash_values array stored into the
				 * .undef.hash section that is ordered as the
				 * undefined symbols of the .symtab
				 */
				hash_values++;
			}
		}
	}
}
Пример #2
0
/*
 * Convert an Elf_Sym into an nlist structure.  This fills in only the
 * n_value and n_type members.
 */
static void
elf_sym_to_nlist(struct nlist *nl, Elf_Sym *s, Elf_Shdr *shdr, int shnum)
{
	nl->n_value = s->st_value;

	switch (s->st_shndx) {
	case SHN_UNDEF:
	case SHN_COMMON:
		nl->n_type = N_UNDF;
		break;
	case SHN_ABS:
		nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ?
		    N_FN : N_ABS;
		break;
	default:
		if (s->st_shndx >= shnum)
			nl->n_type = N_UNDF;
		else {
			Elf_Shdr *sh = shdr + s->st_shndx;

			nl->n_type = sh->sh_type == SHT_PROGBITS ?
			    (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) :
			    (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF);
		}
		break;
	}

	if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
	    ELF_ST_BIND(s->st_info) == STB_WEAK)
		nl->n_type |= N_EXT;
}
Пример #3
0
static void
link_elf_reloc_local(linker_file_t lf)
{
	elf_file_t ef = (elf_file_t)lf;
	const Elf_Rel *rellim;
	const Elf_Rel *rel;
	const Elf_Rela *relalim;
	const Elf_Rela *rela;
	const Elf_Sym *sym;
	Elf_Addr base;
	int i;
	Elf_Size symidx;

	link_elf_fix_link_set(ef);

	/* Perform relocations without addend if there are any: */
	for (i = 0; i < ef->nreltab; i++) {
		rel = ef->reltab[i].rel;
		if (rel == NULL)
			panic("lost a reltab!");
		rellim = rel + ef->reltab[i].nrel;
		base = findbase(ef, ef->reltab[i].sec);
		if (base == 0)
			panic("lost base for reltab");
		for ( ; rel < rellim; rel++) {
			symidx = ELF_R_SYM(rel->r_info);
			if (symidx >= ef->ddbsymcnt)
				continue;
			sym = ef->ddbsymtab + symidx;
			/* Only do local relocs */
			if (ELF_ST_BIND(sym->st_info) != STB_LOCAL)
				continue;
			elf_reloc_local(lf, base, rel, ELF_RELOC_REL,
			    elf_obj_lookup);
		}
	}

	/* Perform relocations with addend if there are any: */
	for (i = 0; i < ef->nrelatab; i++) {
		rela = ef->relatab[i].rela;
		if (rela == NULL)
			panic("lost a relatab!");
		relalim = rela + ef->relatab[i].nrela;
		base = findbase(ef, ef->relatab[i].sec);
		if (base == 0)
			panic("lost base for relatab");
		for ( ; rela < relalim; rela++) {
			symidx = ELF_R_SYM(rela->r_info);
			if (symidx >= ef->ddbsymcnt)
				continue;
			sym = ef->ddbsymtab + symidx;
			/* Only do local relocs */
			if (ELF_ST_BIND(sym->st_info) != STB_LOCAL)
				continue;
			elf_reloc_local(lf, base, rela, ELF_RELOC_RELA,
			    elf_obj_lookup);
		}
	}
}
Пример #4
0
static bool
wantsym(const Elf_Sym *sym, const char *strtab)
{
    int type;
    int bind;

    type = ELF_ST_TYPE(sym->st_info);
    bind = ELF_ST_BIND(sym->st_info);

    if (type != STT_FUNC || (aflag && bind == STB_LOCAL))
#if 0
 ||
      (uflag && strchr(strtab + sym->st_name, '.') != NULL))
#endif
	return 0;

#ifdef __arm__
    /* ignore what gas calls "mapping symbols" */
    {
	const char *c = strtab + sym->st_name;
	if (c[0] == '$')
	    return 0;
    }
#endif

    return 1;
}
Пример #5
0
Elf32_Sym *mips_elf_find_address(struct mips_cpu *pcpu, Elf32_Addr addr)
{
	Elf32_Shdr *shsymtab = pcpu->shsymtab;
	unsigned    n = shsymtab->sh_size / shsymtab->sh_entsize;
	Elf32_Addr  min = (unsigned)-1;
	Elf32_Sym  *ret = NULL;
	unsigned    i;

	if((shsymtab->sh_offset  + shsymtab->sh_size > pcpu->elfsz)
	|| (addr >= pcpu->memsz))
		return NULL;
	
	for(i = 0; i < n; i++) {
		Elf32_Sym  *sym = get_sym(pcpu->elf, pcpu->elfsz, shsymtab, i);

		if(!sym)
			return NULL;
		if((ELF_ST_BIND(sym->st_info) != STB_GLOBAL) ||
				(ELF_ST_TYPE(sym->st_info) >= STT_SECTION))
			continue;
		
		if(sym->st_value <= addr) {
			Elf32_Addr diff = addr - sym->st_value;
			
			if(diff < min) {
				min = diff;
				ret = sym;
				if(diff == 0)
					break;
			}
		}
	}
	return ret;
}
Пример #6
0
Elf32_Sym *mips_elf_find_symbol(struct mips_cpu *pcpu, const char *name)
{
	Elf32_Shdr *shsymtab = pcpu->shsymtab;
	unsigned    n =shsymtab->sh_size / shsymtab->sh_entsize;
	unsigned    i;
	
	if(shsymtab->sh_offset  + shsymtab->sh_size > pcpu->elfsz)
		return NULL;
	
	for(i = 0; i < n; i++) {
	    Elf32_Sym  *sym = get_sym(pcpu->elf, pcpu->elfsz, shsymtab, i);
	    const char *symname;

	    if(!sym)
			return NULL;
	    if(ELF_ST_BIND(sym->st_info) != STB_GLOBAL)
			continue;
		
	    symname = get_string(pcpu->elf, pcpu->elfsz,
				pcpu->shsymstr, sym->st_name);
	    if(!symname)
			return NULL;
	    if(Sequal(name, symname))
			return sym;
	}
	return NULL;
}
Пример #7
0
int sym7(void)
{
	if(ELF_ST_TYPE(orcSYM->st_info) != STT_FILE)
		return 0;

	if(mode & REL)
		if(rand() % 2)
			return 0;

	unsigned char st_info = orcSYM->st_info;
	Elf_Section st_shndx;

	if(rand() % 2)
		do
			st_info = ELF_ST_INFO(rand() & 0x0f, STT_FILE);
		while(ELF_ST_BIND(st_info) == STB_LOCAL);

	if(rand() % 4 < 3){
		while((st_shndx = rand() % orcHDR->e_shnum))
			if(st_shndx != SHN_ABS)
				break;
	} else
		while((st_shndx = getElf_Section()))
			if(st_shndx != SHN_ABS)
				break;

	orcSYM->st_info  = st_info;
	orcSYM->st_shndx = st_shndx;

	fprintf(logfp, "(SYM[%d]->st_info = 0x%.2x,", entry, orcSYM->st_info);
	fprintf(logfp, " st_shndx = 0x%x)", orcSYM->st_shndx);

	return 1;
}
Пример #8
0
    bool
    generic_get_symbol( Elf_Xword index,
                        std::string& name, Elf64_Addr& value,
                        Elf_Xword& size,
                        unsigned char& bind, unsigned char& type,
                        Elf_Half& section_index,
                        unsigned char& other ) const
    {
        bool ret = false;

        if ( index < get_symbols_num() ) {
            const T* pSym = reinterpret_cast<const T*>(
                symbol_section->get_data() +
                    index * symbol_section->get_entry_size() );

            const endianess_convertor& convertor = elf_file.get_convertor();

            section* string_section = elf_file.sections[get_string_table_index()];
            string_section_accessor str_reader( string_section );
            const char* pStr = str_reader.get_string( convertor( pSym->st_name ) );
            if ( 0 != pStr ) {
                name = pStr;
            }
            value   = convertor( pSym->st_value );
            size    = convertor( pSym->st_size );
            bind    = ELF_ST_BIND( pSym->st_info );
            type    = ELF_ST_TYPE( pSym->st_info );
            section_index = convertor( pSym->st_shndx );
            other   = pSym->st_other;

            ret = true;
        }

        return ret;
    }
Пример #9
0
/*
 * Symbol lookup function that can be used when the symbol index is known (ie
 * in relocations). It uses the symbol index instead of doing a fully fledged
 * hash table based lookup when such is valid. For example for local symbols.
 * This is not only more efficient, it's also more correct. It's not always
 * the case that the symbol can be found through the hash table.
 */
static Elf_Addr
elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps)
{
	elf_file_t ef = (elf_file_t)lf;
	Elf_Sym *sym;
	const char *symbol;
	Elf_Addr ret;

	/* Don't even try to lookup the symbol if the index is bogus. */
	if (symidx >= ef->ddbsymcnt)
		return (0);

	sym = ef->ddbsymtab + symidx;

	/* Quick answer if there is a definition included. */
	if (sym->st_shndx != SHN_UNDEF)
		return (sym->st_value);

	/* If we get here, then it is undefined and needs a lookup. */
	switch (ELF_ST_BIND(sym->st_info)) {
	case STB_LOCAL:
		/* Local, but undefined? huh? */
		return (0);

	case STB_GLOBAL:
		/* Relative to Data or Function name */
		symbol = ef->ddbstrtab + sym->st_name;

		/* Force a lookup failure if the symbol name is bogus. */
		if (*symbol == 0)
			return (0);
		ret = ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));

		/*
		 * Cache global lookups during module relocation. The failure
		 * case is particularly expensive for callers, who must scan
		 * through the entire globals table doing strcmp(). Cache to
		 * avoid doing such work repeatedly.
		 *
		 * After relocation is complete, undefined globals will be
		 * restored to SHN_UNDEF in elf_obj_cleanup_globals_cache(),
		 * above.
		 */
		if (ret != 0) {
			sym->st_shndx = SHN_FBSD_CACHED;
			sym->st_value = ret;
		}
		return (ret);

	case STB_WEAK:
		printf("link_elf_obj: Weak symbols not supported\n");
		return (0);

	default:
		return (0);
	}
}
Пример #10
0
/*
 * kobj_sym_lookup:
 *
 *	Symbol lookup function to be used when the symbol index
 *	is known (ie during relocation).
 */
uintptr_t
kobj_sym_lookup(kobj_t ko, uintptr_t symidx)
{
	const Elf_Sym *sym;
	const char *symbol;
	int error;
	u_long addr;

	/* Don't even try to lookup the symbol if the index is bogus. */
	if (symidx >= ko->ko_symcnt)
		return 0;

	sym = ko->ko_symtab + symidx;

	/* Quick answer if there is a definition included. */
	if (sym->st_shndx != SHN_UNDEF) {
		return sym->st_value;
	}

	/* If we get here, then it is undefined and needs a lookup. */
	switch (ELF_ST_BIND(sym->st_info)) {
	case STB_LOCAL:
		/* Local, but undefined? huh? */
		kobj_error("local symbol undefined");
		return 0;

	case STB_GLOBAL:
		/* Relative to Data or Function name */
		symbol = ko->ko_strtab + sym->st_name;

		/* Force a lookup failure if the symbol name is bogus. */
		if (*symbol == 0) {
			kobj_error("bad symbol name");
			return 0;
		}

		/*
		 * Don't need to lock, as it is known that the symbol
		 * tables aren't going to change (we hold module_lock).
		 */
		error = ksyms_getval(NULL, symbol, &addr, KSYMS_ANY);
		if (error != 0) {
			kobj_error("symbol `%s' not found", symbol);
			return (uintptr_t)0;
		}
		return (uintptr_t)addr;

	case STB_WEAK:
		kobj_error("weak symbols not supported\n");
		return 0;

	default:
		return 0;
	}
}
Пример #11
0
static void parse_elf_symbols(uintptr_t mem, size_t size, Phdr_t *load,
		struct vdso_symtable *t, uintptr_t dynsymbol_names,
		Hash_t *hash, Dyn_t *dyn_symtab)
{
	const char *vdso_symbols[VDSO_SYMBOL_MAX] = {
		ARCH_VDSO_SYMBOLS
	};
	const size_t vdso_symbol_length = sizeof(t->symbols[0].name);

	Hash_t nbucket, nchain;
	Hash_t *bucket, *chain;

	unsigned int i, j, k;
	uintptr_t addr;

	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]) {
			addr = mem + dyn_symtab->d_un.d_ptr - load->p_vaddr;
			Sym_t *sym;
			char *name;

			addr += sizeof(Sym_t)*j;
			if (__ptr_struct_oob(addr, sizeof(Sym_t), mem, size))
				continue;
			sym = (void *)addr;

			if (ELF_ST_TYPE(sym->st_info) != STT_FUNC &&
			    ELF_ST_BIND(sym->st_info) != STB_GLOBAL)
				continue;

			addr = dynsymbol_names + sym->st_name;
			if (__ptr_struct_oob(addr, vdso_symbol_length, mem, size))
				continue;
			name = (void *)addr;

			if (std_strncmp(name, symbol, vdso_symbol_length))
				continue;

			memcpy(t->symbols[i].name, name, vdso_symbol_length);
			t->symbols[i].offset = (unsigned long)sym->st_value - load->p_vaddr;
			break;
		}
	}
}
Пример #12
0
static int simplify_symbols(struct secthdr *sechdrs,
			    unsigned int symindex,
			    const char *strtab,
			    unsigned int versindex,
			    unsigned int pcpuindex, struct module *mod)
{
	struct symtab_s *sym = (void *)sechdrs[symindex].sh_addr;
	unsigned long secbase;
	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(struct symtab_s);
	int ret = 0;
	const struct kernel_symbol *ksym;
	for (i = 1; i < n; i++) {
		switch (sym[i].st_shndx) {
		case SHN_COMMON:
			/* We compiled with -fno-common.  These are not supposed to happen.  */
			kprintf("simplify_symbols: Common symbol: %s\n",
				strtab + sym[i].st_name);
			kprintf("%s: please compile with -fno-common\n",
				mod->name);
			ret = -1;
			break;
		case SHN_ABS:
			/* Don't need to do anything */
			kprintf("simplify_symbols: Absolute symbol: 0x%08lx\n",
				(long)sym[i].st_value);
			break;
		case SHN_UNDEF:
			ksym =
			    resolve_symbol(sechdrs, versindex,
					   strtab + sym[i].st_name, mod);
			/* Ok if resolved.  */
			if (ksym) {
				sym[i].st_value = ksym->value;
				break;
			}
			/* Ok if weak. */
			if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
				break;
			kprintf("simplify_symbols: Unknown symbol %s\n",
				strtab + sym[i].st_name);
			ret = -1;
			break;
		default:
			if (sym[i].st_shndx == pcpuindex)
				secbase = (unsigned long)mod->percpu;
			else
				secbase = sechdrs[sym[i].st_shndx].sh_addr;
			sym[i].st_value += secbase;
			break;
		}
	}
	return ret;
}
Пример #13
0
static bool
wantsym(const Elf_Sym *sym, const char *strtab)
{
    int type;
    int bind;

    type = ELF_ST_TYPE(sym->st_info);
    bind = ELF_ST_BIND(sym->st_info);

    if (type != STT_FUNC ||
      (aflag && bind == STB_LOCAL) ||
      (uflag && strchr(strtab + sym->st_name, '.') != NULL))
	return 0;

    return 1;
}
Пример #14
0
static Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi,
					    const char *name)
{
	Elf_Sym *syms;
	Elf_Shdr *sechdrs;
	Elf_Ehdr *ehdr;
	int i, k;
	const char *strtab;

	if (!pi->sechdrs || !pi->ehdr)
		return NULL;

	sechdrs = pi->sechdrs;
	ehdr = pi->ehdr;

	for (i = 0; i < ehdr->e_shnum; i++) {
		if (sechdrs[i].sh_type != SHT_SYMTAB)
			continue;

		if (sechdrs[i].sh_link >= ehdr->e_shnum)
			/* Invalid strtab section number */
			continue;
		strtab = (char *)sechdrs[sechdrs[i].sh_link].sh_offset;
		syms = (Elf_Sym *)sechdrs[i].sh_offset;

		/* Go through symbols for a match */
		for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) {
			if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL)
				continue;

			if (strcmp(strtab + syms[k].st_name, name) != 0)
				continue;

			if (syms[k].st_shndx == SHN_UNDEF ||
			    syms[k].st_shndx >= ehdr->e_shnum) {
				pr_debug("Symbol: %s has bad section index %d.\n",
						name, syms[k].st_shndx);
				return NULL;
			}

			/* Found the symbol we are looking for */
			return &syms[k];
		}
	}

	return NULL;
}
Пример #15
0
void* dlsym(void* handle, const char* symbol) {
  ScopedPthreadMutexLocker locker(&g_dl_mutex);

#if !defined(__LP64__)
  if (handle == NULL) {
    __bionic_format_dlerror("dlsym library handle is null", NULL);
    return NULL;
  }
#endif

  if (symbol == NULL) {
    __bionic_format_dlerror("dlsym symbol name is null", NULL);
    return NULL;
  }

  soinfo* found = NULL;
  ElfW(Sym)* sym = NULL;
  if (handle == RTLD_DEFAULT) {
    sym = dlsym_linear_lookup(symbol, &found, NULL);
  } else if (handle == RTLD_NEXT) {
    void* caller_addr = __builtin_return_address(0);
    soinfo* si = find_containing_library(caller_addr);

    sym = NULL;
    if (si && si->next) {
      sym = dlsym_linear_lookup(symbol, &found, si->next);
    }
  } else {
    found = reinterpret_cast<soinfo*>(handle);
    sym = dlsym_handle_lookup(found, symbol);
  }

  if (sym != NULL) {
    unsigned bind = ELF_ST_BIND(sym->st_info);

    if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
      return reinterpret_cast<void*>(sym->st_value + found->load_bias);
    }

    __bionic_format_dlerror("symbol found but not global", symbol);
    return NULL;
  } else {
    __bionic_format_dlerror("undefined symbol", symbol);
    return NULL;
  }
}
Пример #16
0
/*
 * kobj_sym_lookup:
 *
 *	Symbol lookup function to be used when the symbol index
 *	is known (ie during relocation).
 */
uintptr_t
kobj_sym_lookup(kobj_t ko, uintptr_t symidx)
{
	const Elf_Sym *sym;
	const char *symbol;

	/* Don't even try to lookup the symbol if the index is bogus. */
	if (symidx >= ko->ko_symcnt)
		return 0;

	sym = ko->ko_symtab + symidx;

	/* Quick answer if there is a definition included. */
	if (sym->st_shndx != SHN_UNDEF) {
		return (uintptr_t)sym->st_value;
	}

	/* If we get here, then it is undefined and needs a lookup. */
	switch (ELF_ST_BIND(sym->st_info)) {
	case STB_LOCAL:
		/* Local, but undefined? huh? */
		kobj_error(__func__, __LINE__, ko, "local symbol undefined");
		return 0;

	case STB_GLOBAL:
		/* Relative to Data or Function name */
		symbol = ko->ko_strtab + sym->st_name;

		/* Force a lookup failure if the symbol name is bogus. */
		if (*symbol == 0) {
			kobj_error(__func__, __LINE__, ko, "bad symbol name");
			return 0;
		}

		return (uintptr_t)sym->st_value;

	case STB_WEAK:
		kobj_error(__func__, __LINE__, ko,
		    "weak symbols not supported");
		return 0;

	default:
		return 0;
	}
}
Пример #17
0
/*
 * kobj_checkdup:
 *
 *	Scan symbol table for duplicates.
 */
static int
kobj_checkdup(kobj_t ko)
{
	unsigned long rval;
	Elf_Sym *sym, *ms;
	const char *name;
	bool dup;

	dup = false;
	for (ms = (sym = ko->ko_symtab) + ko->ko_symcnt; sym < ms; sym++) {
		/* Check validity of the symbol. */
		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL ||
		    sym->st_name == 0)
			continue;

		/* Check if the symbol already exists */
		name = ko->ko_strtab + sym->st_name;
		if (ksyms_getval(NULL, name, &rval, KSYMS_EXTERN) != 0) {
			continue;
		}

		/* Check (and complain) about differing values */
		if (sym->st_value == rval || sym->st_shndx == SHN_UNDEF) {
			continue;
		}
		if (strcmp(name, "_bss_start") == 0 ||
		    strcmp(name, "__bss_start") == 0 ||
		    strcmp(name, "_bss_end__") == 0 ||
		    strcmp(name, "__bss_end__") == 0 ||
		    strcmp(name, "_edata") == 0 ||
		    strcmp(name, "_end") == 0 ||
		    strcmp(name, "__end") == 0 ||
		    strcmp(name, "__end__") == 0 ||
		    strncmp(name, "__start_link_set_", 17) == 0 ||
		    strncmp(name, "__stop_link_set_", 16)) {
		    	continue;
		}
		kobj_error("global symbol `%s' redefined\n", name);
		dup = true;
	}

	return dup ? EEXIST : 0;
}
Пример #18
0
/*
 * Symbol lookup function that can be used when the symbol index is known (ie
 * in relocations). It uses the symbol index instead of doing a fully fledged
 * hash table based lookup when such is valid. For example for local symbols.
 * This is not only more efficient, it's also more correct. It's not always
 * the case that the symbol can be found through the hash table.
 */
static int
elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps, Elf_Addr *result)
{
	elf_file_t ef = lf->priv;
	const Elf_Sym *sym;
	const char *symbol;

	/* Don't even try to lookup the symbol if the index is bogus. */
	if (symidx >= ef->ddbsymcnt)
		return (ENOENT);

	sym = ef->ddbsymtab + symidx;

	/* Quick answer if there is a definition included. */
	if (sym->st_shndx != SHN_UNDEF) {
		*result = sym->st_value;
		return (0);
	}

	/* If we get here, then it is undefined and needs a lookup. */
	switch (ELF_ST_BIND(sym->st_info)) {
	case STB_LOCAL:
		/* Local, but undefined? huh? */
		return (ENOENT);

	case STB_GLOBAL:
		/* Relative to Data or Function name */
		symbol = ef->ddbstrtab + sym->st_name;

		/* Force a lookup failure if the symbol name is bogus. */
		if (*symbol == 0)
			return (ENOENT);
		return (linker_file_lookup_symbol(lf, symbol, deps, (caddr_t *)result));

	case STB_WEAK:
		kprintf("link_elf_obj_obj: Weak symbols not supported\n");
		return (ENOENT);

	default:
		return (ENOENT);
	}
}
Пример #19
0
/**
 * @brief dump the absolute symbols to the header file
 *
 * @param fd file descriptor of file from which to read
 * @param fp file pointer to which to write
 * @param symTblOffset symbol table offset
 * @param symTblSize size of the symbol table
 * @param pStringTable ptr to the string table
 * @returns N/A
 */
static void headerAbsoluteSymbolsDump(int fd, FILE *fp, Elf32_Off symTblOffset,
		Elf32_Word symTblSize, char *pStringTable)
{
	Elf32_Sym  aSym;     /* absolute symbol */
	unsigned   ix;       /* loop counter */
	unsigned   numSyms;  /* number of symbols in the symbol table */
	size_t	   nBytes;

	/* context the symbol table: pick out absolute syms */

	numSyms = symTblSize / sizeof(Elf32_Sym);
	lseek(fd, symTblOffset, SEEK_SET);

	for (ix = 0; ix < numSyms; ++ix)
	{
		/* read in a single symbol structure */
		nBytes = read(fd, &aSym, sizeof(Elf32_Sym));

		if (nBytes) {
			swabElfSym(&aSym);    /* swap bytes (if required) */
		}

		/*
		 * Only generate definitions for global absolute symbols
		 * of the form *_OFFSET
		 */

		if ((aSym.st_shndx == SHN_ABS) &&
				(ELF_ST_BIND(aSym.st_info) == STB_GLOBAL))
		{
			if ((strstr(&pStringTable[aSym.st_name],
							STRUCT_OFF_SUFFIX) != NULL) ||
					(strstr(&pStringTable[aSym.st_name],
						 STRUCT_SIZ_SUFFIX) != NULL))
			{
				fprintf(fp, "#define\t%s\t0x%X\n",
						&pStringTable[aSym.st_name], aSym.st_value);
			}
		}
	}
}
Пример #20
0
int sym6(void)
{
	if(ELF_ST_TYPE(orcSYM->st_info) != STT_SECTION)
		return 0;

	if(mode & REL)
		if(rand() % 2)
			return 0;

	unsigned char st_info;

	do
		st_info = ELF_ST_INFO(rand() & 0x0f, STT_SECTION);
	while(ELF_ST_BIND(st_info) == STB_LOCAL);

	orcSYM->st_info = st_info;

	fprintf(logfp, "(SYM[%d]->st_info = 0x%.2x)", entry, orcSYM->st_info);

	return 1;
}
Пример #21
0
/*
 * Symbol lookup function that can be used when the symbol index is known (ie
 * in relocations). It uses the symbol index instead of doing a fully fledged
 * hash table based lookup when such is valid. For example for local symbols.
 * This is not only more efficient, it's also more correct. It's not always
 * the case that the symbol can be found through the hash table.
 */
static int
elf_lookup(linker_file_t lf, Elf_Size symidx, int deps, Elf_Addr *result)
{
    elf_file_t	    ef = lf->priv;
    const Elf_Sym  *sym;
    const char     *symbol;

    /* Don't even try to lookup the symbol if the index is bogus. */
    if (symidx >= ef->nchains)
	return (ENOENT);

    sym = ef->symtab + symidx;

    /*
     * Don't do a full lookup when the symbol is local. It may even
     * fail because it may not be found through the hash table.
     */
    if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
	/* Force lookup failure when we have an insanity. */
	if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0)
	    return (ENOENT);
	return ((Elf_Addr) ef->address + sym->st_value);
    }
    /*
     * XXX we can avoid doing a hash table based lookup for global
     * symbols as well. This however is not always valid, so we'll
     * just do it the hard way for now. Performance tweaks can
     * always be added.
     */

    symbol = ef->strtab + sym->st_name;

    /* Force a lookup failure if the symbol name is bogus. */
    if (*symbol == 0)
	return (ENOENT);

    return (linker_file_lookup_symbol(lf, symbol, deps, (caddr_t *)result));
}
Пример #22
0
/*ARGSUSED*/
static void
ksyms_walk_one(void *arg, void *base, size_t size)
{
	ksyms_walkinfo_t *kwp = arg;
	Shdr *symhdr = base;
	Shdr *strhdr = symhdr + symhdr->sh_link;
	size_t symsize = symhdr->sh_entsize;
	size_t nsyms = symhdr->sh_size / symsize;
	char *strings = (char *)strhdr->sh_addr;
	int i;

	for (i = 1; i < nsyms; i++) {
		Sym *sym = (Sym *)(symhdr->sh_addr + i * symsize);
		Sym tmp = *sym;
		char *name = strings + sym->st_name;
		tmp.st_name = kwp->kw_size[KW_STRINGS];
		tmp.st_shndx = SHN_ABS;
		ksyms_emit(kwp, &tmp, sizeof (Sym),
		    ELF_ST_BIND(sym->st_info) == STB_LOCAL ?
		    KW_LOCALS : KW_GLOBALS);
		ksyms_emit(kwp, name, strlen(name) + 1, KW_STRINGS);
	}
}
Пример #23
0
/*
 * Warning message for bad move target.
 */
void
elf_move_bad(Lm_list *lml, Rt_map *lmp, Sym *sym, ulong_t num, Addr addr)
{
	const char	*name;
	int		trace;

	trace = (lml->lm_flags & LML_FLG_TRC_ENABLE) &&
	    (((rtld_flags & RT_FL_SILENCERR) == 0) ||
	    (lml->lm_flags & (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_WARN)));

	if ((trace == 0) && (DBG_ENABLED == 0))
		return;

	if (ELF_ST_BIND(sym->st_info) != STB_LOCAL)
		name = (const char *)(STRTAB(lmp) + sym->st_name);
	else
		name = MSG_INTL(MSG_STR_UNKNOWN);

	if (trace)
		(void) printf(MSG_INTL(MSG_LDD_MOVE_ERR), EC_XWORD(num), name,
		    EC_ADDR(addr));
	else
		DBG_CALL(Dbg_move_bad(lml, num, name, addr));
}
Пример #24
0
int
_dl_md_reloc(elf_object_t *object, int rel, int relasz)
{
	long	i;
	long	numrela;
	int	fails = 0;
	Elf64_Addr loff;
	Elf64_Rela  *relas;
	struct load_list *llist;

	loff = object->obj_base;
	numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela);
	relas = (Elf64_Rela *)(object->Dyn.info[rel]);

	if (relas == NULL)
		return(0);

	/*
	 * unprotect some segments if we need it.
	 * XXX - we unprotect way to much. only the text can have cow
	 * relocations.
	 */
	if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL; llist = llist->next) {
			if (!(llist->prot & PROT_WRITE)) {
				_dl_mprotect(llist->start, llist->size,
				    llist->prot|PROT_WRITE);
			}
		}
	}

	for (i = 0; i < numrela; i++, relas++) {
		Elf64_Addr *r_addr;
		Elf64_Addr ooff;
		const Elf64_Sym *sym, *this;
		const char *symn;

		r_addr = (Elf64_Addr *)(relas->r_offset + loff);

		if (ELF64_R_SYM(relas->r_info) == 0xffffffff)
			continue;


		sym = object->dyn.symtab;
		sym += ELF64_R_SYM(relas->r_info);
		symn = object->dyn.strtab + sym->st_name;

		this = NULL;
		switch (ELF64_R_TYPE(relas->r_info)) {
		case R_TYPE(REFQUAD):
			ooff =  _dl_find_symbol_bysym(object,
			    ELF64_R_SYM(relas->r_info), &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
			    sym, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr += ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(RELATIVE):
			/*
			 * There is a lot of unaligned RELATIVE
			 * relocs generated by gcc in the exception handlers.
			 */
			if ((((Elf_Addr) r_addr) & 0x7) != 0) {
				Elf_Addr tmp;
#if 0
_dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr,
    ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff);
#endif
				_dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
				tmp += loff;
				_dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
			} else
				*r_addr += loff;
			break;
		case R_TYPE(JMP_SLOT):
			ooff = _dl_find_symbol(symn, &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
			    sym, object, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr = ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(GLOB_DAT):
			ooff =  _dl_find_symbol_bysym(object,
			    ELF64_R_SYM(relas->r_info), &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
			    sym, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr = ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(NONE):
			break;
		default:
			_dl_printf("%s:"
			    " %s: unsupported relocation '%s' %d at %lx\n",
			    _dl_progname, object->load_name, symn,
			    ELF64_R_TYPE(relas->r_info), r_addr );
			_dl_exit(1);
		}
		continue;
resolve_failed:
		if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
			fails++;
	}
	__asm __volatile("imb" : : : "memory");

	/* reprotect the unprotected segments */
	if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL; llist = llist->next) {
			if (!(llist->prot & PROT_WRITE))
				_dl_mprotect(llist->start, llist->size,
				    llist->prot);
		}
	}
	return (fails);
}
Пример #25
0
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
	const Elf_Rel *rel = 0, *rellim;
	Elf_Addr relsz = 0;
	const Elf_Sym *symtab = NULL, *sym;
	Elf_Addr *where;
	Elf_Addr *got = NULL;
	Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
	size_t i;

	for (; dynp->d_tag != DT_NULL; dynp++) {
		switch (dynp->d_tag) {
		case DT_REL:
			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_RELSZ:
			relsz = dynp->d_un.d_val;
			break;
		case DT_SYMTAB:
			symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_PLTGOT:
			got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_MIPS_LOCAL_GOTNO:
			local_gotno = dynp->d_un.d_val;
			break;
		case DT_MIPS_SYMTABNO:
			symtabno = dynp->d_un.d_val;
			break;
		case DT_MIPS_GOTSYM:
			gotsym = dynp->d_un.d_val;
			break;
		}
	}

	i = (got[1] & GOT1_MASK) ? 2 : 1;
	/* Relocate the local GOT entries */
	got += i;
	for (; i < local_gotno; i++) {
		*got++ += relocbase;
	}

	sym = symtab + gotsym;
	/* Now do the global GOT entries */
	for (i = gotsym; i < symtabno; i++) {
		*got = sym->st_value + relocbase;
		++sym;
		++got;
	}

	rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
	for (; rel < rellim; rel++) {
		Elf_Word r_symndx, r_type;

		where = (void *)(relocbase + rel->r_offset);

		r_symndx = ELF_R_SYM(rel->r_info);
		r_type = ELF_R_TYPE(rel->r_info);

		switch (r_type & 0xff) {
		case R_TYPE(REL32): {
			const size_t rlen =
			    ELF_R_NXTTYPE_64_P(r_type)
				? sizeof(Elf_Sxword)
				: sizeof(Elf_Sword);
			Elf_Sxword old = load_ptr(where, rlen);
			Elf_Sxword val = old;
#ifdef __mips_n64
			assert(r_type == R_TYPE(REL32)
			    || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8)));
#endif
			assert(r_symndx < gotsym);
			sym = symtab + r_symndx;
			assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
			val += relocbase;
			store_ptr(where, val, sizeof(Elf_Sword));
			dbg("REL32/L(%p) %p -> %p in <self>",
			    where, (void *)old, (void *)val);
			store_ptr(where, val, rlen);
			break;
		}

		case R_TYPE(GPREL32):
		case R_TYPE(NONE):
			break;


		default:
			abort();
			break;
		}
	}
}
Пример #26
0
/*
 * Read and process the relocations for one link object, we assume all
 * relocation sections for loadable segments are stored contiguously in
 * the file.
 */
int
elf_reloc(Rt_map *lmp, uint_t plt, int *in_nfavl, APlist **textrel)
{
	ulong_t		relbgn, relend, relsiz, basebgn, pltbgn, pltend;
	ulong_t		_pltbgn, _pltend;
	ulong_t		dsymndx, roffset, rsymndx, psymndx = 0;
	uchar_t		rtype;
	long		value, pvalue;
	Sym		*symref, *psymref, *symdef, *psymdef;
	Syminfo		*sip;
	char		*name, *pname;
	Rt_map		*_lmp, *plmp;
	int		ret = 1, noplt = 0;
	int		relacount = RELACOUNT(lmp), plthint = 0;
	Rel		*rel;
	uint_t		binfo, pbinfo;
	APlist		*bound = NULL;

	/*
	 * Although only necessary for lazy binding, initialize the first
	 * global offset entry to go to elf_rtbndr().  dbx(1) seems
	 * to find this useful.
	 */
	if ((plt == 0) && PLTGOT(lmp)) {
		mmapobj_result_t	*mpp;

		/*
		 * Make sure the segment is writable.
		 */
		if ((((mpp =
		    find_segment((caddr_t)PLTGOT(lmp), lmp)) != NULL) &&
		    ((mpp->mr_prot & PROT_WRITE) == 0)) &&
		    ((set_prot(lmp, mpp, 1) == 0) ||
		    (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL)))
			return (0);

		elf_plt_init(PLTGOT(lmp), (caddr_t)lmp);
	}

	/*
	 * Initialize the plt start and end addresses.
	 */
	if ((pltbgn = (ulong_t)JMPREL(lmp)) != 0)
		pltend = pltbgn + (ulong_t)(PLTRELSZ(lmp));

	relsiz = (ulong_t)(RELENT(lmp));
	basebgn = ADDR(lmp);

	if (PLTRELSZ(lmp))
		plthint = PLTRELSZ(lmp) / relsiz;

	/*
	 * If we've been called upon to promote an RTLD_LAZY object to an
	 * RTLD_NOW then we're only interested in scaning the .plt table.
	 * An uninitialized .plt is the case where the associated got entry
	 * points back to the plt itself.  Determine the range of the real .plt
	 * entries using the _PROCEDURE_LINKAGE_TABLE_ symbol.
	 */
	if (plt) {
		Slookup	sl;
		Sresult	sr;

		relbgn = pltbgn;
		relend = pltend;
		if (!relbgn || (relbgn == relend))
			return (1);

		/*
		 * Initialize the symbol lookup, and symbol result, data
		 * structures.
		 */
		SLOOKUP_INIT(sl, MSG_ORIG(MSG_SYM_PLT), lmp, lmp, ld_entry_cnt,
		    elf_hash(MSG_ORIG(MSG_SYM_PLT)), 0, 0, 0, LKUP_DEFT);
		SRESULT_INIT(sr, MSG_ORIG(MSG_SYM_PLT));

		if (elf_find_sym(&sl, &sr, &binfo, NULL) == 0)
			return (1);

		symdef = sr.sr_sym;
		_pltbgn = symdef->st_value;
		if (!(FLAGS(lmp) & FLG_RT_FIXED) &&
		    (symdef->st_shndx != SHN_ABS))
			_pltbgn += basebgn;
		_pltend = _pltbgn + (((PLTRELSZ(lmp) / relsiz)) *
		    M_PLT_ENTSIZE) + M_PLT_RESERVSZ;

	} else {
		/*
		 * The relocation sections appear to the run-time linker as a
		 * single table.  Determine the address of the beginning and end
		 * of this table.  There are two different interpretations of
		 * the ABI at this point:
		 *
		 *   o	The REL table and its associated RELSZ indicate the
		 *	concatenation of *all* relocation sections (this is the
		 *	model our link-editor constructs).
		 *
		 *   o	The REL table and its associated RELSZ indicate the
		 *	concatenation of all *but* the .plt relocations.  These
		 *	relocations are specified individually by the JMPREL and
		 *	PLTRELSZ entries.
		 *
		 * Determine from our knowledege of the relocation range and
		 * .plt range, the range of the total relocation table.  Note
		 * that one other ABI assumption seems to be that the .plt
		 * relocations always follow any other relocations, the
		 * following range checking drops that assumption.
		 */
		relbgn = (ulong_t)(REL(lmp));
		relend = relbgn + (ulong_t)(RELSZ(lmp));
		if (pltbgn) {
			if (!relbgn || (relbgn > pltbgn))
				relbgn = pltbgn;
			if (!relbgn || (relend < pltend))
				relend = pltend;
		}
	}
	if (!relbgn || (relbgn == relend)) {
		DBG_CALL(Dbg_reloc_run(lmp, 0, plt, DBG_REL_NONE));
		return (1);
	}
	DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, plt, DBG_REL_START));

	/*
	 * If we're processing a dynamic executable in lazy mode there is no
	 * need to scan the .rel.plt table, however if we're processing a shared
	 * object in lazy mode the .got addresses associated to each .plt must
	 * be relocated to reflect the location of the shared object.
	 */
	if (pltbgn && ((MODE(lmp) & RTLD_NOW) == 0) &&
	    (FLAGS(lmp) & FLG_RT_FIXED))
		noplt = 1;

	sip = SYMINFO(lmp);
	/*
	 * Loop through relocations.
	 */
	while (relbgn < relend) {
		mmapobj_result_t	*mpp;
		uint_t			sb_flags = 0;

		rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info, M_MACH);

		/*
		 * If this is a RELATIVE relocation in a shared object (the
		 * common case), and if we are not debugging, then jump into a
		 * tighter relocation loop (elf_reloc_relative).
		 */
		if ((rtype == R_386_RELATIVE) &&
		    ((FLAGS(lmp) & FLG_RT_FIXED) == 0) && (DBG_ENABLED == 0)) {
			if (relacount) {
				relbgn = elf_reloc_relative_count(relbgn,
				    relacount, relsiz, basebgn, lmp,
				    textrel, 0);
				relacount = 0;
			} else {
				relbgn = elf_reloc_relative(relbgn, relend,
				    relsiz, basebgn, lmp, textrel, 0);
			}
			if (relbgn >= relend)
				break;
			rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info, M_MACH);
		}

		roffset = ((Rel *)relbgn)->r_offset;

		/*
		 * If this is a shared object, add the base address to offset.
		 */
		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
			/*
			 * If we're processing lazy bindings, we have to step
			 * through the plt entries and add the base address
			 * to the corresponding got entry.
			 */
			if (plthint && (plt == 0) &&
			    (rtype == R_386_JMP_SLOT) &&
			    ((MODE(lmp) & RTLD_NOW) == 0)) {
				relbgn = elf_reloc_relative_count(relbgn,
				    plthint, relsiz, basebgn, lmp, textrel, 0);
				plthint = 0;
				continue;
			}
			roffset += basebgn;
		}

		rsymndx = ELF_R_SYM(((Rel *)relbgn)->r_info);
		rel = (Rel *)relbgn;
		relbgn += relsiz;

		/*
		 * Optimizations.
		 */
		if (rtype == R_386_NONE)
			continue;
		if (noplt && ((ulong_t)rel >= pltbgn) &&
		    ((ulong_t)rel < pltend)) {
			relbgn = pltend;
			continue;
		}

		/*
		 * If we're promoting plts, determine if this one has already
		 * been written.
		 */
		if (plt && ((*(ulong_t *)roffset < _pltbgn) ||
		    (*(ulong_t *)roffset > _pltend)))
			continue;

		/*
		 * If this relocation is not against part of the image
		 * mapped into memory we skip it.
		 */
		if ((mpp = find_segment((caddr_t)roffset, lmp)) == NULL) {
			elf_reloc_bad(lmp, (void *)rel, rtype, roffset,
			    rsymndx);
			continue;
		}

		binfo = 0;
		/*
		 * If a symbol index is specified then get the symbol table
		 * entry, locate the symbol definition, and determine its
		 * address.
		 */
		if (rsymndx) {
			/*
			 * If a Syminfo section is provided, determine if this
			 * symbol is deferred, and if so, skip this relocation.
			 */
			if (sip && is_sym_deferred((ulong_t)rel, basebgn, lmp,
			    textrel, sip, rsymndx))
				continue;

			/*
			 * Get the local symbol table entry.
			 */
			symref = (Sym *)((ulong_t)SYMTAB(lmp) +
			    (rsymndx * SYMENT(lmp)));

			/*
			 * If this is a local symbol, just use the base address.
			 * (we should have no local relocations in the
			 * executable).
			 */
			if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) {
				value = basebgn;
				name = NULL;

				/*
				 * Special case TLS relocations.
				 */
				if (rtype == R_386_TLS_DTPMOD32) {
					/*
					 * Use the TLS modid.
					 */
					value = TLSMODID(lmp);

				} else if (rtype == R_386_TLS_TPOFF) {
					if ((value = elf_static_tls(lmp, symref,
					    rel, rtype, 0, roffset, 0)) == 0) {
						ret = 0;
						break;
					}
				}
			} else {
				/*
				 * If the symbol index is equal to the previous
				 * symbol index relocation we processed then
				 * reuse the previous values. (Note that there
				 * have been cases where a relocation exists
				 * against a copy relocation symbol, our ld(1)
				 * should optimize this away, but make sure we
				 * don't use the same symbol information should
				 * this case exist).
				 */
				if ((rsymndx == psymndx) &&
				    (rtype != R_386_COPY)) {
					/* LINTED */
					if (psymdef == 0) {
						DBG_CALL(Dbg_bind_weak(lmp,
						    (Addr)roffset, (Addr)
						    (roffset - basebgn), name));
						continue;
					}
					/* LINTED */
					value = pvalue;
					/* LINTED */
					name = pname;
					/* LINTED */
					symdef = psymdef;
					/* LINTED */
					symref = psymref;
					/* LINTED */
					_lmp = plmp;
					/* LINTED */
					binfo = pbinfo;

					if ((LIST(_lmp)->lm_tflags |
					    AFLAGS(_lmp)) &
					    LML_TFLG_AUD_SYMBIND) {
						value = audit_symbind(lmp, _lmp,
						    /* LINTED */
						    symdef, dsymndx, value,
						    &sb_flags);
					}
				} else {
					Slookup		sl;
					Sresult		sr;

					/*
					 * Lookup the symbol definition.
					 * Initialize the symbol lookup, and
					 * symbol result, data structures.
					 */
					name = (char *)(STRTAB(lmp) +
					    symref->st_name);

					SLOOKUP_INIT(sl, name, lmp, 0,
					    ld_entry_cnt, 0, rsymndx, symref,
					    rtype, LKUP_STDRELOC);
					SRESULT_INIT(sr, name);
					symdef = NULL;

					if (lookup_sym(&sl, &sr, &binfo,
					    in_nfavl)) {
						name = (char *)sr.sr_name;
						_lmp = sr.sr_dmap;
						symdef = sr.sr_sym;
					}

					/*
					 * If the symbol is not found and the
					 * reference was not to a weak symbol,
					 * report an error.  Weak references
					 * may be unresolved.
					 */
					/* BEGIN CSTYLED */
					if (symdef == 0) {
					    if (sl.sl_bind != STB_WEAK) {
						if (elf_reloc_error(lmp, name,
						    rel, binfo))
							continue;

					   	ret = 0;
						break;

					    } else {
						psymndx = rsymndx;
						psymdef = 0;

						DBG_CALL(Dbg_bind_weak(lmp,
						    (Addr)roffset, (Addr)
						    (roffset - basebgn), name));
						continue;
					    }
					}
					/* END CSTYLED */

					/*
					 * If symbol was found in an object
					 * other than the referencing object
					 * then record the binding.
					 */
					if ((lmp != _lmp) && ((FLAGS1(_lmp) &
					    FL1_RT_NOINIFIN) == 0)) {
						if (aplist_test(&bound, _lmp,
						    AL_CNT_RELBIND) == 0) {
							ret = 0;
							break;
						}
					}

					/*
					 * Calculate the location of definition;
					 * symbol value plus base address of
					 * containing shared object.
					 */
					if (IS_SIZE(rtype))
						value = symdef->st_size;
					else
						value = symdef->st_value;

					if (!(FLAGS(_lmp) & FLG_RT_FIXED) &&
					    !(IS_SIZE(rtype)) &&
					    (symdef->st_shndx != SHN_ABS) &&
					    (ELF_ST_TYPE(symdef->st_info) !=
					    STT_TLS))
						value += ADDR(_lmp);

					/*
					 * Retain this symbol index and the
					 * value in case it can be used for the
					 * subsequent relocations.
					 */
					if (rtype != R_386_COPY) {
						psymndx = rsymndx;
						pvalue = value;
						pname = name;
						psymdef = symdef;
						psymref = symref;
						plmp = _lmp;
						pbinfo = binfo;
					}
					if ((LIST(_lmp)->lm_tflags |
					    AFLAGS(_lmp)) &
					    LML_TFLG_AUD_SYMBIND) {
						dsymndx = (((uintptr_t)symdef -
						    (uintptr_t)SYMTAB(_lmp)) /
						    SYMENT(_lmp));
						value = audit_symbind(lmp, _lmp,
						    symdef, dsymndx, value,
						    &sb_flags);
					}
				}

				/*
				 * If relocation is PC-relative, subtract
				 * offset address.
				 */
				if (IS_PC_RELATIVE(rtype))
					value -= roffset;

				/*
				 * Special case TLS relocations.
				 */
				if (rtype == R_386_TLS_DTPMOD32) {
					/*
					 * Relocation value is the TLS modid.
					 */
					value = TLSMODID(_lmp);

				} else if (rtype == R_386_TLS_TPOFF) {
					if ((value = elf_static_tls(_lmp,
					    symdef, rel, rtype, name, roffset,
					    value)) == 0) {
						ret = 0;
						break;
					}
				}
			}
		} else {
			/*
			 * Special cases.
			 */
			if (rtype == R_386_TLS_DTPMOD32) {
				/*
				 * TLS relocation value is the TLS modid.
				 */
				value = TLSMODID(lmp);
			} else
				value = basebgn;

			name = NULL;
		}

		DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH,
		    M_REL_SHT_TYPE, rel, NULL, 0, name));

		/*
		 * Make sure the segment is writable.
		 */
		if (((mpp->mr_prot & PROT_WRITE) == 0) &&
		    ((set_prot(lmp, mpp, 1) == 0) ||
		    (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) {
			ret = 0;
			break;
		}

		/*
		 * Call relocation routine to perform required relocation.
		 */
		switch (rtype) {
		case R_386_COPY:
			if (elf_copy_reloc(name, symref, lmp, (void *)roffset,
			    symdef, _lmp, (const void *)value) == 0)
				ret = 0;
			break;
		case R_386_JMP_SLOT:
			if (((LIST(lmp)->lm_tflags | AFLAGS(lmp)) &
			    (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) &&
			    AUDINFO(lmp)->ai_dynplts) {
				int	fail = 0;
				int	pltndx = (((ulong_t)rel -
				    (uintptr_t)JMPREL(lmp)) / relsiz);
				int	symndx = (((uintptr_t)symdef -
				    (uintptr_t)SYMTAB(_lmp)) / SYMENT(_lmp));

				(void) elf_plt_trace_write(roffset, lmp, _lmp,
				    symdef, symndx, pltndx, (caddr_t)value,
				    sb_flags, &fail);
				if (fail)
					ret = 0;
			} else {
				/*
				 * Write standard PLT entry to jump directly
				 * to newly bound function.
				 */
				DBG_CALL(Dbg_reloc_apply_val(LIST(lmp),
				    ELF_DBG_RTLD, (Xword)roffset,
				    (Xword)value));
				*(ulong_t *)roffset = value;
			}
			break;
		default:
			/*
			 * Write the relocation out.
			 */
			if (do_reloc_rtld(rtype, (uchar_t *)roffset,
			    (Word *)&value, name, NAME(lmp), LIST(lmp)) == 0)
				ret = 0;

			DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), ELF_DBG_RTLD,
			    (Xword)roffset, (Xword)value));
		}

		if ((ret == 0) &&
		    ((LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) == 0))
			break;

		if (binfo) {
			DBG_CALL(Dbg_bind_global(lmp, (Addr)roffset,
			    (Off)(roffset - basebgn), (Xword)(-1), PLT_T_FULL,
			    _lmp, (Addr)value, symdef->st_value, name, binfo));
		}
	}

	return (relocate_finish(lmp, bound, ret));
}
Пример #27
0
static int
relocate_file(elf_file_t ef)
{
	const Elf_Rel *rellim;
	const Elf_Rel *rel;
	const Elf_Rela *relalim;
	const Elf_Rela *rela;
	const char *symname;
	const Elf_Sym *sym;
	int i;
	Elf_Size symidx;
	Elf_Addr base;


	/* Perform relocations without addend if there are any: */
	for (i = 0; i < ef->nreltab; i++) {
		rel = ef->reltab[i].rel;
		if (rel == NULL)
			panic("lost a reltab!");
		rellim = rel + ef->reltab[i].nrel;
		base = findbase(ef, ef->reltab[i].sec);
		if (base == 0)
			panic("lost base for reltab");
		for ( ; rel < rellim; rel++) {
			symidx = ELF_R_SYM(rel->r_info);
			if (symidx >= ef->ddbsymcnt)
				continue;
			sym = ef->ddbsymtab + symidx;
			/* Local relocs are already done */
			if (ELF_ST_BIND(sym->st_info) == STB_LOCAL)
				continue;
			if (elf_reloc(&ef->lf, base, rel, ELF_RELOC_REL,
			    elf_obj_lookup)) {
				symname = symbol_name(ef, rel->r_info);
				printf("link_elf_obj: symbol %s undefined\n",
				    symname);
				return ENOENT;
			}
		}
	}

	/* Perform relocations with addend if there are any: */
	for (i = 0; i < ef->nrelatab; i++) {
		rela = ef->relatab[i].rela;
		if (rela == NULL)
			panic("lost a relatab!");
		relalim = rela + ef->relatab[i].nrela;
		base = findbase(ef, ef->relatab[i].sec);
		if (base == 0)
			panic("lost base for relatab");
		for ( ; rela < relalim; rela++) {
			symidx = ELF_R_SYM(rela->r_info);
			if (symidx >= ef->ddbsymcnt)
				continue;
			sym = ef->ddbsymtab + symidx;
			/* Local relocs are already done */
			if (ELF_ST_BIND(sym->st_info) == STB_LOCAL)
				continue;
			if (elf_reloc(&ef->lf, base, rela, ELF_RELOC_RELA,
			    elf_obj_lookup)) {
				symname = symbol_name(ef, rela->r_info);
				printf("link_elf_obj: symbol %s undefined\n",
				    symname);
				return ENOENT;
			}
		}
	}

	/*
	 * Only clean SHN_FBSD_CACHED for successfull return.  If we
	 * modified symbol table for the object but found an
	 * unresolved symbol, there is no reason to roll back.
	 */
	elf_obj_cleanup_globals_cache(ef);

	return 0;
}
Пример #28
0
int
__elf_fdnlist(int fd, struct nlist *list)
{
	struct nlist *p;
	caddr_t strtab;
	Elf_Off symoff = 0, symstroff = 0;
	Elf_Word symsize = 0, symstrsize = 0;
	Elf_Sword nent, cc, i;
	Elf_Sym sbuf[1024];
	Elf_Sym *s;
	Elf_Ehdr ehdr;
	Elf_Shdr *shdr = NULL;
	Elf_Word shdr_size;
	struct stat st;
	int usemalloc = 0;

	/* Make sure obj is OK */
	if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) ||
	    !__elf_is_okay__(&ehdr) || fstat(fd, &st) < 0)
		return (-1);

	/* calculate section header table size */
	shdr_size = ehdr.e_shentsize * ehdr.e_shnum;

	/* Make sure it's not too big to mmap */
	if (shdr_size > SIZE_T_MAX) {
		errno = EFBIG;
		return (-1);
	}

	/* mmap section header table */
	shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ,
	    MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff);
	if (shdr == MAP_FAILED) {
		usemalloc = 1;
		if ((shdr = malloc(shdr_size)) == NULL)
			return (-1);

		if (pread(fd, shdr, shdr_size, (off_t)ehdr.e_shoff) != shdr_size) {
			free(shdr);
			return (-1);
		}
	}

	/*
	 * Find the symbol table entry and its corresponding
	 * string table entry.	Version 1.1 of the ABI states
	 * that there is only one symbol table but that this
	 * could change in the future.
	 */
	for (i = 0; i < ehdr.e_shnum; i++) {
		if (shdr[i].sh_type == SHT_SYMTAB) {
			symoff = shdr[i].sh_offset;
			symsize = shdr[i].sh_size;
			symstroff = shdr[shdr[i].sh_link].sh_offset;
			symstrsize = shdr[shdr[i].sh_link].sh_size;
			break;
		}
	}

	/* Flush the section header table */
	if (usemalloc)
		free(shdr);
	else
		munmap((caddr_t)shdr, shdr_size);

	/* Check for files too large to mmap. */
	/* XXX is this really possible? */
	if (symstrsize > SIZE_T_MAX) {
		errno = EFBIG;
		return (-1);
	}
	/*
	 * Map string table into our address space.  This gives us
	 * an easy way to randomly access all the strings, without
	 * making the memory allocation permanent as with malloc/free
	 * (i.e., munmap will return it to the system).
	 */
	if (usemalloc) {
		if ((strtab = malloc(symstrsize)) == NULL)
			return (-1);
		if (pread(fd, strtab, symstrsize, (off_t)symstroff) != symstrsize) {
			free(strtab);
			return (-1);
		}
	} else {
		strtab = mmap(NULL, (size_t)symstrsize, PROT_READ,
		    MAP_SHARED|MAP_FILE, fd, (off_t) symstroff);
		if (strtab == MAP_FAILED)
			return (-1);
	}
	/*
	 * clean out any left-over information for all valid entries.
	 * Type and value defined to be 0 if not found; historical
	 * versions cleared other and desc as well.  Also figure out
	 * the largest string length so don't read any more of the
	 * string table than we have to.
	 *
	 * XXX clearing anything other than n_type and n_value violates
	 * the semantics given in the man page.
	 */
	nent = 0;
	for (p = list; !ISLAST(p); ++p) {
		p->n_type = 0;
		p->n_other = 0;
		p->n_desc = 0;
		p->n_value = 0;
		++nent;
	}

	/* Don't process any further if object is stripped. */
	/* ELFism - dunno if stripped by looking at header */
	if (symoff == 0)
		goto elf_done;

	while (symsize > 0) {
		cc = MIN(symsize, sizeof(sbuf));
		if (pread(fd, sbuf, cc, (off_t)symoff) != cc)
			break;
		symsize -= cc;
		symoff += cc;
		for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) {
			int soff = s->st_name;

			if (soff == 0)
				continue;
			for (p = list; !ISLAST(p); p++) {
				char *sym;

				/*
				 * First we check for the symbol as it was
				 * provided by the user. If that fails
				 * and the first char is an '_', skip over
				 * the '_' and try again.
				 * XXX - What do we do when the user really
				 *       wants '_foo' and the are symbols
				 *       for both 'foo' and '_foo' in the
				 *	 table and 'foo' is first?
				 */
				sym = p->n_un.n_name;
				if (strcmp(&strtab[soff], sym) != 0 &&
				    (sym[0] != '_' ||
				     strcmp(&strtab[soff], sym + 1) != 0))
					continue;

				p->n_value = s->st_value;

				/* XXX - type conversion */
				/*	 is pretty rude. */
				switch(ELF_ST_TYPE(s->st_info)) {
				case STT_NOTYPE:
					switch (s->st_shndx) {
					case SHN_UNDEF:
						p->n_type = N_UNDF;
						break;
					case SHN_ABS:
						p->n_type = N_ABS;
						break;
					case SHN_COMMON:
						p->n_type = N_COMM;
						break;
					default:
						p->n_type = N_COMM | N_EXT;
						break;
					}
					break;
				case STT_OBJECT:
					p->n_type = N_DATA;
					break;
				case STT_FUNC:
					p->n_type = N_TEXT;
					break;
				case STT_FILE:
					p->n_type = N_FN;
					break;
				}
				if (ELF_ST_BIND(s->st_info) ==
				    STB_LOCAL)
					p->n_type = N_EXT;
				p->n_desc = 0;
				p->n_other = 0;
				if (--nent <= 0)
					break;
			}
		}
	}
elf_done:
	if (usemalloc)
		free(strtab);
	else
		munmap(strtab, symstrsize);
	return (nent);
}
Пример #29
0
uintptr_t
ld_group_process(Is_desc *gisc, Ofl_desc *ofl)
{
	Ifl_desc	*gifl = gisc->is_file;
	Shdr		*sshdr, *gshdr = gisc->is_shdr;
	Is_desc		*isc;
	Sym		*sym;
	const char	*str;
	Group_desc	gd;
	size_t		ndx;
	int		gnu_stt_section;

	/*
	 * Confirm that the sh_link points to a valid section.
	 */
	if ((gshdr->sh_link == SHN_UNDEF) ||
	    (gshdr->sh_link >= gifl->ifl_shnum) ||
	    ((isc = gifl->ifl_isdesc[gshdr->sh_link]) == NULL)) {
		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHLINK),
		    gifl->ifl_name, EC_WORD(gisc->is_scnndx),
		    gisc->is_name, EC_XWORD(gshdr->sh_link));
		return (0);
	}
	if (gshdr->sh_entsize == 0) {
		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHENTSIZE),
		    gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name,
		    EC_XWORD(gshdr->sh_entsize));
		return (0);
	}

	/*
	 * Get the associated symbol table.  Sanity check the sh_info field
	 * (which points to the signature symbol table entry) against the size
	 * of the symbol table.
	 */
	sshdr = isc->is_shdr;
	sym = (Sym *)isc->is_indata->d_buf;

	if ((sshdr->sh_info == SHN_UNDEF) ||
	    (gshdr->sh_info >= (Word)(sshdr->sh_size / sshdr->sh_entsize)) ||
	    ((isc = gifl->ifl_isdesc[sshdr->sh_link]) == NULL)) {
		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHINFO),
		    gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name,
		    EC_XWORD(gshdr->sh_info));
		return (0);
	}

	sym += gshdr->sh_info;

	/*
	 * Get the symbol name from the associated string table.
	 */
	str = (char *)isc->is_indata->d_buf;
	str += sym->st_name;

	/*
	 * The GNU assembler can use section symbols as the signature symbol
	 * as described by this comment in the gold linker (found via google):
	 *
	 *	It seems that some versions of gas will create a section group
	 *	associated with a section symbol, and then fail to give a name
	 *	to the section symbol.  In such a case, use the name of the
	 *	section.
	 *
	 * In order to support such objects, we do the same.
	 */
	gnu_stt_section = ((sym->st_name == 0) || (*str == '\0')) &&
	    (ELF_ST_TYPE(sym->st_info) == STT_SECTION);
	if (gnu_stt_section)
		str = gisc->is_name;


	/*
	 * Generate a group descriptor.
	 */
	gd.gd_isc = gisc;
	gd.gd_oisc = NULL;
	gd.gd_name = str;
	gd.gd_data = gisc->is_indata->d_buf;
	gd.gd_cnt = gisc->is_indata->d_size / sizeof (Word);

	/*
	 * If this group is a COMDAT group, validate the signature symbol.
	 */
	if ((gd.gd_data[0] & GRP_COMDAT) && !gnu_stt_section &&
	    ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) ||
	    (sym->st_shndx == SHN_UNDEF))) {
		/* If section symbol, construct a printable name for it */
		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
			if (gisc->is_sym_name == NULL)
				(void) ld_stt_section_sym_name(gisc);

			if (gisc->is_sym_name != NULL)
				str = gisc->is_sym_name;
		}

		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_GRP_INVALSYM),
		    gifl->ifl_name, EC_WORD(gisc->is_scnndx),
		    gisc->is_name, str);
		return (0);
	}

	/*
	 * If the signature symbol is a name generated by the GNU compiler to
	 * refer to a header, we need sloppy relocation.
	 */
	if (is_header_gensym(str)) {
		if ((ofl->ofl_flags1 & FLG_OF1_NRLXREL) == 0)
			ofl->ofl_flags1 |= FLG_OF1_RLXREL;
		DBG_CALL(Dbg_sec_gnu_comdat(ofl->ofl_lml, gisc, TRUE,
		    (ofl->ofl_flags1 & FLG_OF1_RLXREL) != 0));
	}

	/*
	 * Validate the section indices within the group.  If this is a COMDAT
	 * group, mark each section as COMDAT.
	 */
	for (ndx = 1; ndx < gd.gd_cnt; ndx++) {
		Word	gndx;

		if ((gndx = gd.gd_data[ndx]) >= gifl->ifl_shnum) {
			ld_eprintf(ofl, ERR_FATAL,
			    MSG_INTL(MSG_GRP_INVALNDX), gifl->ifl_name,
			    EC_WORD(gisc->is_scnndx), gisc->is_name, ndx, gndx);
			return (0);
		}

		if (gd.gd_data[0] & GRP_COMDAT)
			gifl->ifl_isdesc[gndx]->is_flags |= FLG_IS_COMDAT;
	}

	/*
	 * If this is a COMDAT group, determine whether this group has already
	 * been encountered, or whether this is the first instance of the group.
	 */
	if ((gd.gd_data[0] & GRP_COMDAT) &&
	    (gpavl_loaded(ofl, &gd) == S_ERROR))
		return (S_ERROR);

	/*
	 * Associate the group descriptor with this input file.
	 */
	if (alist_append(&(gifl->ifl_groups), &gd, sizeof (Group_desc),
	    AL_CNT_IFL_GROUPS) == NULL)
		return (S_ERROR);

	return (1);
}
Пример #30
0
/*
 * Devise nlist's type from Elf_Sym.
 * XXX this task is done as well in libc and kvm_mkdb.
 */
int
elf2nlist(Elf_Sym *sym, const Elf_Ehdr *eh, const Elf_Shdr *shdr,
          const char *shstr, struct nlist *np)
{
    u_int stt;
    const char *sn;
    int type;

    if (sym->st_shndx < eh->e_shnum)
        sn = shstr + shdr[sym->st_shndx].sh_name;
    else
        sn = NULL;

    switch (stt = ELF_ST_TYPE(sym->st_info)) {
    case STT_NOTYPE:
    case STT_OBJECT:
        type = elf_shn2type(eh, sym->st_shndx, sn);
        if (type < 0) {
            if (sn == NULL)
                np->n_other = '?';
            else
                np->n_type = stt == STT_NOTYPE? N_COMM : N_DATA;
        } else {
            /* a hack for .rodata check (; */
            if (type == N_SIZE) {
                np->n_type = N_DATA;
                np->n_other = 'r';
            } else
                np->n_type = type;
        }
        break;

    case STT_FUNC:
        type = elf_shn2type(eh, sym->st_shndx, sn);
        np->n_type = type < 0? N_TEXT : type;
        if (type < 0)
            np->n_other = 't';
        if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
            np->n_type = N_INDR;
            np->n_other = 'W';
        } else if (sn != NULL && *sn != 0 &&
                   strcmp(sn, ELF_INIT) &&
                   strcmp(sn, ELF_TEXT) &&
                   strcmp(sn, ELF_FINI))	/* XXX GNU compat */
            np->n_other = '?';
        break;

    case STT_SECTION:
        type = elf_shn2type(eh, sym->st_shndx, NULL);
        if (type < 0)
            np->n_other = '?';
        else
            np->n_type = type;
        break;

    case STT_FILE:
        np->n_type = N_FN | N_EXT;
        break;

    case STT_PARISC_MILLI:
        if (eh->e_machine == EM_PARISC)
            np->n_type = N_TEXT;
        else
            np->n_other = '?';
        break;

    default:
        np->n_other = '?';
        break;
    }
    if ((np->n_type & N_TYPE) != N_UNDF &&
            ELF_ST_BIND(sym->st_info) != STB_LOCAL) {
        np->n_type |= N_EXT;
        if (np->n_other)
            np->n_other = toupper(np->n_other);
    }

    np->n_value = sym->st_value;
    np->n_un.n_strx = sym->st_name;
    return (0);
}