summaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:29:27 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:29:27 -0800
commit5be48c0aa50b576ea678d9298b5207c9e8854224 (patch)
treed37ee9e0c10b3abce0ff0f4f4f0a3d6e851be688 /hash.c
parentd1ceeffdc951169c079c2d35f8b8cd26481dcc3a (diff)
downloadelfcopy-5be48c0aa50b576ea678d9298b5207c9e8854224.tar.gz
auto import from //depot/cupcake/@135843
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/hash.c b/hash.c
new file mode 100644
index 0000000..e2cffcc
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,76 @@
+#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <hash.h>
+#include <string.h>
+
+void setup_hash(Elf_Data *hash_data,
+ Elf32_Word nbuckets,
+ Elf32_Word nchains)
+{
+ hash_data->d_size = 2;
+ hash_data->d_size += nbuckets;
+ hash_data->d_size += nchains;
+ hash_data->d_buf = CALLOC(hash_data->d_size, sizeof(Elf32_Word));
+ hash_data->d_size *= sizeof(Elf32_Word);
+ ((Elf32_Word *)hash_data->d_buf)[0] = nbuckets;
+ ((Elf32_Word *)hash_data->d_buf)[1] = nchains;
+}
+
+void add_to_hash(Elf_Data *hash_data,
+ const char *symbol,
+ int symindex)
+{
+ Elf32_Word *buckets = (Elf32_Word *)hash_data->d_buf;
+ Elf32_Word nbuckets = *buckets++;
+ Elf32_Word *chains = ++buckets + nbuckets;
+ Elf32_Word last_chain_index;
+ unsigned long bucket = elf_hash(symbol) % nbuckets;
+
+ ASSERT(symindex != STN_UNDEF);
+
+ if (buckets[bucket] == STN_UNDEF) {
+ INFO("Adding [%s] to hash at bucket [%ld] (first add)\n",
+ symbol, bucket);
+ buckets[bucket] = symindex;
+ }
+ else {
+ INFO("Collision on adding [%s] to hash at bucket [%ld]\n",
+ symbol, bucket);
+ last_chain_index = buckets[bucket];
+ while (chains[last_chain_index] != STN_UNDEF) {
+ INFO("\ttrying at chain index [%d]...\n", last_chain_index);
+ last_chain_index = chains[last_chain_index];
+ }
+ INFO("\tsuccess at chain index [%d]...\n", last_chain_index);
+ chains[last_chain_index] = symindex;
+ }
+}
+
+int hash_lookup(Elf *elf,
+ section_info_t *hash_info,
+ section_info_t *symtab_info,
+ const char *symname,
+ GElf_Sym *sym_mem)
+{
+ Elf32_Word *hash_data = (Elf32_Word *)hash_info->data->d_buf;
+ Elf32_Word index;
+ Elf32_Word nbuckets = *hash_data++;
+ Elf32_Word *buckets = ++hash_data;
+ Elf32_Word *chains = hash_data + nbuckets;
+
+ GElf_Sym *sym;
+
+ index = buckets[elf_hash(symname) % nbuckets];
+ while(index != STN_UNDEF)
+ {
+ sym = gelf_getsymshndx (symtab_info->data, NULL, index, sym_mem, NULL);
+ FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
+ if (!strcmp(symname,
+ elf_strptr(elf, symtab_info->hdr->sh_link, sym->st_name)))
+ break;
+ index = chains[index];
+ }
+
+ return index;
+}