2011/8/22 Bernhard Rosenkranzer <bernhard.rosenkran...@linaro.org>:
> On 21 August 2011 15:00, Michael Hope <michael.h...@linaro.org> wrote:
>> Sorry, silly question, but does Android use the glibc dynamic linker?
>
> No, they really like reinventing the wheel. Bionic comes with its own
> dynamic linker.

hi Bernhard and Michael,

The dynamic linker is file "/system/bin/linker".

>> If not, does its linker support other hash styles?
>
> It looks like it supports both the sysv and gnu styles. It uses libelf
> to do most of its ELF parsing, and libelf seems to do the right thing.

I don't think so.  Since Android uses the libelfcopy[2], derived from
some really old parts in binutils, providing the
facilities about DWARF/ELF, we would need extra modifications like the
attached patch.[*]

Also, bionic linker changes are required.  Another attachment contains
the 0xlab internal modifications.

Sincerely,
-jserv

[*] The related patches are expected to be submitted to AOSP Gerrit recently.
From 71f965b55ffaaa0853e60be2e8b97daf95544712 Mon Sep 17 00:00:00 2001
From: Kito Cheng <k...@0xlab.org>
Date: Fri, 12 Aug 2011 00:55:37 +0800
Subject: [PATCH] Basic GNU-style hash support for elfcopy

---
 elfcopy.c |   17 +++++++++++++++--
 1 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/elfcopy.c b/elfcopy.c
index ed1e6ce..cac10ea 100644
--- a/elfcopy.c
+++ b/elfcopy.c
@@ -34,6 +34,16 @@
 */
 #define ELF_STRPTR_IS_BROKEN     (1)
 
+/* Compatible for older elfutils.
+   elfutils support gnu-style hash since version 0.122
+*/
+#ifndef DT_GNU_HASH
+#define DT_GNU_HASH 0x6ffffef5
+#endif
+#ifndef SHT_GNU_HASH
+#define SHT_GNU_HASH 0x6ffffff6
+#endif
+
 static void update_relocations_section_symbol_references(Elf *newelf, Elf *elf,
                                                          shdr_info_t *info, int info_len,
                                                          shdr_info_t *relsect_info,
@@ -744,7 +754,6 @@ void adjust_elf(Elf *elf, const char *elf_name,
 
                 FAILIF(shdr_info[cnt].shdr.sh_entsize != sizeof (Elf32_Word),
                        "Can't handle 64-bit ELF files!\n");
-
                 update_hash_table(newelf,  /* new ELF */
                                   elf,     /* old ELF */
                                   shdr_info[cnt].idx, /* hash table index */
@@ -846,7 +855,9 @@ void adjust_elf(Elf *elf, const char *elf_name,
                     } /* for each symbol... */
                 }
             }
-
+            /* We don't support update gnu-style hash table now! */
+            FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_HASH,
+                   "Can't handle SHT_GNU_HASH!\n");
             FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_versym,
                    "Can't handle SHT_GNU_versym!\n");
             FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GROUP,
@@ -1933,6 +1944,7 @@ static void adjust_dynamic_segment_offsets(Elf *elf, Ebl *oldebl,
 
         case DT_PLTGOT:
         case DT_HASH:
+        case DT_GNU_HASH:
         case DT_SYMTAB:
             (void)update_dyn_entry_address(elf, dyn, shdr_info, shdr_info_len);
             break;
@@ -2582,6 +2594,7 @@ static int get_end_of_range(shdr_info_t *shdr_info,
             (shdr_info[end].shdr.sh_type == SHT_INIT_ARRAY) ||
             (shdr_info[end].shdr.sh_type == SHT_FINI_ARRAY) ||
             (shdr_info[end].shdr.sh_type == SHT_PREINIT_ARRAY) ||
+            (shdr_info[end].shdr.sh_type == SHT_GNU_HASH) ||
          /* (shdr_info[end].shdr.sh_type == SHT_NOBITS) || */
 #ifdef ARM_SPECIFIC_HACKS
             /* SHF_ALLOC sections with with names starting with ".ARM." are
-- 
1.7.5.4

From 5bf2ca212750d3dadac96de0bfd4d621abbb0dea Mon Sep 17 00:00:00 2001
From: Kito Cheng <k...@0xlab.org>
Date: Fri, 12 Aug 2011 00:49:57 +0800
Subject: [PATCH] GNU-style hash support for linker

---
 linker/linker.c       |  116 ++++++++++++++++++++++++++++++++++++++++++++++---
 linker/linker.h       |    7 +++
 linker/linker_debug.h |   17 +++++++
 3 files changed, 133 insertions(+), 7 deletions(-)

diff --git a/linker/linker.c b/linker/linker.c
index bb31703..d5fc459 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -62,6 +62,13 @@
 #define LDPRELOAD_BUFSIZE 512
 #define LDPRELOAD_MAX 8
 
+/* Compatible for older elfutils.
+   elfutils support gnu-style hash since version 0.122
+*/
+#ifndef DT_GNU_HASH
+#define DT_GNU_HASH	0x6ffffef5  /* address of gnu-style symbol hash table */
+#endif
+
 /* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
  *
  * Do NOT use malloc() and friends or pthread_*() code here.
@@ -399,6 +406,54 @@ dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),
 }
 #endif
 
+static Elf32_Sym *_gnu_lookup(soinfo *si, unsigned gnu_hash, const char *name)
+{
+    Elf32_Sym *s;
+    Elf32_Sym *symtab = si->symtab;
+    const char *strtab = si->strtab;
+    int elfclass = 32;
+    Elf32_Word bitmask_word = si->gnu_bitmask[(gnu_hash / elfclass)
+                                              & (si->gnu_bitmask_words - 1)];
+    unsigned hashbit1 = gnu_hash & (elfclass - 1);
+    unsigned hashbit2 = ((gnu_hash >> si->gnu_shift)
+                         & (elfclass - 1));
+    Elf32_Word bucket;
+    Elf32_Word index;
+    /* Bloom Filter */
+    if ((  (bitmask_word >> hashbit1)
+         & (bitmask_word >> hashbit2) & 1) == 0){
+       COUNT_LOOKUP(LOOKUP_BLOOM);
+       return NULL;
+    }
+    TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %s@0x%08x %08x %d\n", pid,
+               name, si->name, si->base, gnu_hash, gnu_hash % si->gnu_nbucket);
+    bucket = si->gnu_bucket[gnu_hash % si->gnu_nbucket];
+    if (bucket != 0) {
+        Elf32_Word *hasharr = &si->gnu_chain[bucket];
+        do {
+            if (((*hasharr ^ gnu_hash) >> 1) == 0){
+                index = hasharr - si->gnu_chain;
+                s = symtab + index;
+                if(strcmp(strtab + s->st_name, name)) continue;
+
+
+                switch(ELF32_ST_BIND(s->st_info)){
+                case STB_GLOBAL:
+                case STB_WEAK:
+                    /* no section == undefined */
+                    if(s->st_shndx == 0) continue;
+
+                    TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid,
+                               name, si->name, s->st_value, s->st_size);
+                    return s;
+                }
+            }
+        } while ((*hasharr++ & 1) == 0);
+    }
+
+    return NULL;
+}
+
 static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
 {
     Elf32_Sym *s;
@@ -430,6 +485,32 @@ static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
     return NULL;
 }
 
+static Elf32_Sym *_symbol_lookup(soinfo *si, unsigned hash, unsigned gnu_hash, const char *name)
+{
+  Elf32_Sym *sym;
+  COUNT_LOOKUP(LOOKUP_NUM);
+  if ( si->gnu_bitmask != NULL ){
+    COUNT_LOOKUP(LOOKUP_GNU);
+    sym = _gnu_lookup(si, gnu_hash, name);
+  } else {
+    COUNT_LOOKUP(LOOKUP_ELF);
+    sym = _elf_lookup(si, hash, name);
+  }
+  if (!sym) COUNT_LOOKUP(LOOKUP_FAIL);
+  return sym;
+}
+
+
+static unsigned gnuhash(const char *_name)
+{
+    const unsigned char *name = (const unsigned char *) _name;
+    unsigned h = 5381;
+    unsigned char ch;
+    while ((ch = *name++) != '\0')
+      h = (h << 5) + h + ch;
+    return h & 0xffffffff;
+}
+
 static unsigned elfhash(const char *_name)
 {
     const unsigned char *name = (const unsigned char *) _name;
@@ -448,6 +529,7 @@ static Elf32_Sym *
 _do_lookup(soinfo *si, const char *name, unsigned *base)
 {
     unsigned elf_hash = elfhash(name);
+    unsigned gnu_hash = gnuhash(name);
     Elf32_Sym *s;
     unsigned *d;
     soinfo *lsi = si;
@@ -462,14 +544,14 @@ _do_lookup(soinfo *si, const char *name, unsigned *base)
      * dynamic linking.  Some systems return the first definition found
      * and some the first non-weak definition.   This is system dependent.
      * Here we return the first definition found for simplicity.  */
-    s = _elf_lookup(si, elf_hash, name);
+    s = _symbol_lookup(si, elf_hash, gnu_hash, name);
     if(s != NULL)
         goto done;
 
     /* Next, look for it in the preloads list */
     for(i = 0; preloads[i] != NULL; i++) {
         lsi = preloads[i];
-        s = _elf_lookup(lsi, elf_hash, name);
+        s = _symbol_lookup(lsi, elf_hash, gnu_hash, name);
         if(s != NULL)
             goto done;
     }
@@ -485,7 +567,7 @@ _do_lookup(soinfo *si, const char *name, unsigned *base)
 
             DEBUG("%5d %s: looking up %s in %s\n",
                   pid, si->name, name, lsi->name);
-            s = _elf_lookup(lsi, elf_hash, name);
+            s = _symbol_lookup(lsi, elf_hash, gnu_hash, name);
             if ((s != NULL) && (s->st_shndx != SHN_UNDEF))
                 goto done;
         }
@@ -500,7 +582,7 @@ _do_lookup(soinfo *si, const char *name, unsigned *base)
         lsi = somain;
         DEBUG("%5d %s: looking up %s in executable %s\n",
               pid, si->name, name, lsi->name);
-        s = _elf_lookup(lsi, elf_hash, name);
+        s = _symbol_lookup(lsi, elf_hash, gnu_hash, name);
     }
 #endif
 
@@ -521,7 +603,7 @@ done:
  */
 Elf32_Sym *lookup_in_library(soinfo *si, const char *name)
 {
-    return _elf_lookup(si, elfhash(name), name);
+    return _symbol_lookup(si, elfhash(name), gnuhash(name), name);
 }
 
 /* This is used by dl_sym().  It performs a global symbol lookup.
@@ -529,6 +611,7 @@ Elf32_Sym *lookup_in_library(soinfo *si, const char *name)
 Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
 {
     unsigned elf_hash = elfhash(name);
+    unsigned gnu_hash = gnuhash(name);
     Elf32_Sym *s = NULL;
     soinfo *si;
 
@@ -540,7 +623,7 @@ Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
     {
         if(si->flags & FLAG_ERROR)
             continue;
-        s = _elf_lookup(si, elf_hash, name);
+        s = _symbol_lookup(si, elf_hash, gnu_hash, name);
         if (s != NULL) {
             *found = si;
             break;
@@ -1824,6 +1907,19 @@ static int link_image(soinfo *si, unsigned wr_offset)
             si->bucket = (unsigned *) (si->base + *d + 8);
             si->chain = (unsigned *) (si->base + *d + 8 + si->nbucket * 4);
             break;
+        case DT_GNU_HASH:
+            {
+                unsigned symbias;
+                si->gnu_nbucket = ((unsigned *) (si->base + *d))[0];
+                symbias  = ((unsigned *) (si->base + *d))[1];
+                si->gnu_bitmask_words = ((unsigned *) (si->base + *d))[2];
+                si->gnu_shift = ((unsigned *) (si->base + *d))[3];
+                si->gnu_bitmask =  (unsigned *) (si->base + *d + 16);
+                si->gnu_bucket = (unsigned *) (si->base + *d + 16 +
+                                               4 * si->gnu_bitmask_words);
+                si->gnu_chain = (si->gnu_bucket + si->gnu_nbucket - symbias);
+            }
+            break;
         case DT_STRTAB:
             si->strtab = (const char *) (si->base + *d);
             break;
@@ -2149,7 +2245,6 @@ unsigned __linker_init(unsigned **elfdata)
         vecs++;
     }
     vecs++;
-
     INFO("[ android linker & debugger ]\n");
     DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata);
 
@@ -2241,6 +2336,13 @@ unsigned __linker_init(unsigned **elfdata)
            linker_stats.reloc[RELOC_RELATIVE],
            linker_stats.reloc[RELOC_COPY],
            linker_stats.reloc[RELOC_SYMBOL]);
+    PRINT("LOOKUP STATS: %s: %d lookup, %d fail, %d elf, %d gnu,"
+          " %d filter by bloom\n", argv[0],
+           linker_stats.lookup[LOOKUP_NUM],
+           linker_stats.lookup[LOOKUP_FAIL],
+           linker_stats.lookup[LOOKUP_ELF],
+           linker_stats.lookup[LOOKUP_GNU],
+           linker_stats.lookup[LOOKUP_BLOOM]);
 #endif
 #if COUNT_PAGES
     {
diff --git a/linker/linker.h b/linker/linker.h
index 8596973..c5adc36 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -114,6 +114,13 @@ struct soinfo
     unsigned *bucket;
     unsigned *chain;
 
+    unsigned gnu_nbucket;
+    unsigned gnu_shift;
+    unsigned gnu_bitmask_words;
+    unsigned *gnu_bitmask;
+    unsigned *gnu_bucket;
+    unsigned *gnu_chain;
+
     unsigned *plt_got;
 
     Elf32_Rel *plt_rel;
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 3f08303..3cd7ae3 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -111,8 +111,16 @@ extern int format_fd(int, const char *, ...);
 #define RELOC_SYMBOL          3
 #define NUM_RELOC_STATS       4
 
+#define LOOKUP_NUM          0
+#define LOOKUP_FAIL         1
+#define LOOKUP_ELF          2
+#define LOOKUP_GNU          3
+#define LOOKUP_BLOOM        4
+#define NUM_LOOKUP_STATS    5
+
 struct _link_stats {
     int reloc[NUM_RELOC_STATS];
+    int lookup[NUM_LOOKUP_STATS];
 };
 extern struct _link_stats linker_stats;
 
@@ -123,8 +131,17 @@ extern struct _link_stats linker_stats;
                 PRINT("Unknown reloc stat requested\n");  \
              }                                            \
            } while(0)
+#define COUNT_LOOKUP(type)                                \
+        do { if (type >= 0 && type < NUM_LOOKUP_STATS) {  \
+                linker_stats.lookup[type] += 1;           \
+             } else  {                                    \
+                PRINT("Unknown lookup stat requested\n"); \
+             }                                            \
+           } while(0)
+
 #else /* !STATS */
 #define COUNT_RELOC(type)     do {} while(0)
+#define COUNT_LOOKUP(type)     do {} while(0)
 #endif /* STATS */
 
 #if TIMING
-- 
1.7.5.4

_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to