Esempio n. 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++;
			}
		}
	}
}
Esempio n. 2
0
static inline
void compute_exported_hash(const struct elf_info *elf, enum ksymtab_type tp)
{

	struct kernel_symbol *sym;
	struct kernel_symbol *start = elf->ksym_tables[tp].start;
	struct kernel_symbol *stop = elf->ksym_tables[tp].stop;

	for (sym = start; sym < stop; sym++)
		sym->hash_value = gnu_hash(GET_KSTRING(sym, elf->kstr_offset));
}
static int fill_hashtable(struct elf_htable *htable,
			struct kernel_symbol *start,
			struct kernel_symbol *stop,
			long s_offset)
{
	struct kernel_symbol *ksym;
	uint32_t nb;
	unsigned long hvalue;
	int last_chain_slot;

	/* sanity check */
	if ((htable->elf_buckets == NULL) || (htable->chains == NULL))
		return -1;
	/* Initialize buckets and chains with -1 that means empty */
	memset(htable->elf_buckets, -1, htable->nbucket * sizeof(uint32_t));
	memset(htable->chains, -1, htable->nchain * sizeof(uint32_t));

	nb = htable->nbucket;
	for (ksym = start, hvalue = 0; ksym < stop; ksym++, hvalue++) {
		const unsigned char *name = GET_KSTRING(ksym, s_offset);
		unsigned long h = gnu_hash(name);
		unsigned long idx = h % nb;
		uint32_t *slot = &htable->elf_buckets[idx];

		/*
		 * Store the index of the export symbol ksym in its
		 * related __ksymtable in the hash table buckets for
		 * using during lookup.
		 * If the slot is alredy used ( != -1) then we have a collision
		 * it needs to create an entry in the chain
		 */
		 if (*slot == EMPTY_SLOT)
			*slot = hvalue;
		else {
			if (handle_collision(htable, *slot, hvalue) < 0)
			/* Something wrong happened */
				return -1;
		}
	}
	/*
	 * Update the chain lenght with the best value
	 * so that we will cut unused entries beyond this upper limit
	 * In the best case, when there are not collisions, htable->chains
	 * will be 0 size... good !
	 */
	/* Look for upper chains empty slot */
	for (last_chain_slot = htable->nchain; --last_chain_slot >= 0 &&
		htable->chains[last_chain_slot] == EMPTY_SLOT;);

	htable->nchain = last_chain_slot + 1;
	debugp("\t> Shortest chain lenght = %d\n", htable->nchain);
	return 0;
}
Esempio n. 4
0
static void* resolve_symbol(const char* library, const char* symbol)
{
    const struct link_map* map = link_map_entry_for_library(library);

    if (!map)
    {
        return NULL;
    }

    const uint32_t* hashtab = get_table(map, DT_GNU_HASH);
    const Elf32_Sym* symtab = get_table(map, DT_SYMTAB);
    const char* strtab = get_table(map, DT_STRTAB);

    uint32_t nbuckets = hashtab[0];
    uint32_t symndx = hashtab[1];
    uint32_t maskwords = hashtab[2];
    // index 3 is used for a 'fast-reject-filter' we just ignore
    const uint32_t* buckets = &hashtab[4 + maskwords];
    const uint32_t* values = &hashtab[4 + maskwords + nbuckets];

    uint32_t hash = gnu_hash(symbol);

    uint32_t chain = buckets[hash % nbuckets];
    if (chain == 0)
    {
        fprintf(stderr, "hash of symbol %s in %s refers to empty chain\n", symbol, library);
        return NULL;
    }

    const Elf32_Sym* sym = &symtab[chain];
    const uint32_t* chain_ptr = &values[chain - symndx];
    do
    {
        if ((hash & ~1) == (*chain_ptr & ~1) && strcmp(symbol, strtab + sym->st_name) == 0)
        {
            return (void*)(map->l_addr + sym->st_value);
        }

        sym += 1;
        chain_ptr += 1;
    } while (sym->st_name & 1); // last bit is set for all but the last entry of the chain

    fprintf(stderr, "failed to resolve symbol %s in %s\n", symbol, library);
    return NULL;
}