auto import from //depot/cupcake/@135843
diff --git a/linker/dlfcn.c b/linker/dlfcn.c
new file mode 100644
index 0000000..cd73d11
--- /dev/null
+++ b/linker/dlfcn.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <dlfcn.h>
+#include <pthread.h>
+#include "linker.h"
+
+/* This file hijacks the symbols stubbed out in libdl.so. */
+
+#define DL_SUCCESS                    0
+#define DL_ERR_CANNOT_FIND_LIBRARY    1
+#define DL_ERR_INVALID_LIBRARY_HANDLE 2
+#define DL_ERR_BAD_SYMBOL_NAME        3
+#define DL_ERR_SYMBOL_NOT_FOUND       4
+#define DL_ERR_SYMBOL_NOT_GLOBAL      5
+
+static const char *dl_errors[] = {
+    [DL_SUCCESS] = NULL,
+    [DL_ERR_CANNOT_FIND_LIBRARY] = "Cannot find library",
+    [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle",
+    [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name",
+    [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found",
+    [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global",
+};
+
+static int dl_last_err = DL_SUCCESS;
+
+#define likely(expr)   __builtin_expect (expr, 1)
+#define unlikely(expr) __builtin_expect (expr, 0)
+
+static pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER;
+
+void *dlopen(const char *filename, int flag) 
+{
+    soinfo *ret;
+
+    pthread_mutex_lock(&dl_lock);
+    ret = find_library(filename);
+    if (unlikely(ret == NULL)) {
+        dl_last_err = DL_ERR_CANNOT_FIND_LIBRARY;
+    } else {
+        ret->refcount++;
+    }
+    pthread_mutex_unlock(&dl_lock);
+    return ret;
+}
+
+const char *dlerror(void)
+{
+    const char *err = dl_errors[dl_last_err];
+    dl_last_err = DL_SUCCESS;
+    return err;
+}
+
+void *dlsym(void *handle, const char *symbol)
+{
+    unsigned base;
+    Elf32_Sym *sym;
+    unsigned bind;
+
+    pthread_mutex_lock(&dl_lock);
+    
+    if(unlikely(handle == 0)) { 
+        dl_last_err = DL_ERR_INVALID_LIBRARY_HANDLE;
+        goto err;
+    }
+    if(unlikely(symbol == 0)) {
+        dl_last_err = DL_ERR_BAD_SYMBOL_NAME;
+        goto err;
+    }
+    
+    if(handle == RTLD_DEFAULT) {
+        sym = lookup(symbol, &base);
+    } else if(handle == RTLD_NEXT) {
+        sym = lookup(symbol, &base);
+    } else {
+        sym = lookup_in_library((soinfo*) handle, symbol);
+        base = ((soinfo*) handle)->base;
+    }
+
+    if(likely(sym != 0)) {
+        bind = ELF32_ST_BIND(sym->st_info);
+    
+        if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) {
+            unsigned ret = sym->st_value + base;
+            pthread_mutex_unlock(&dl_lock);
+            return (void*)ret;
+        }
+
+        dl_last_err = DL_ERR_SYMBOL_NOT_GLOBAL;
+    }
+    else dl_last_err = DL_ERR_SYMBOL_NOT_FOUND;
+
+err:
+    pthread_mutex_unlock(&dl_lock);
+    return 0;
+}
+
+int dlclose(void *handle)
+{
+    pthread_mutex_lock(&dl_lock);
+    (void)unload_library((soinfo*)handle);
+    pthread_mutex_unlock(&dl_lock);
+    return 0;
+}
+
+#if defined(ANDROID_ARM_LINKER)
+//                     0000000 00011111 111112 22222222 233333333334444444444
+//                     0123456 78901234 567890 12345678 901234567890123456789
+#define ANDROID_LIBDL_STRTAB \
+                      "dlopen\0dlclose\0dlsym\0dlerror\0dl_unwind_find_exidx\0"
+
+#elif defined(ANDROID_X86_LINKER)
+//                     0000000 00011111 111112 22222222 2333333333344444
+//                     0123456 78901234 567890 12345678 9012345678901234
+#define ANDROID_LIBDL_STRTAB \
+                      "dlopen\0dlclose\0dlsym\0dlerror\0dl_iterate_phdr\0"
+
+#else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */
+#error Unsupported architecture. Only ARM and x86 are presently supported.
+#endif
+
+
+static Elf32_Sym libdl_symtab[] = {
+      // total length of libdl_info.strtab, including trailing 0
+      // This is actually the the STH_UNDEF entry. Technically, it's
+      // supposed to have st_name == 0, but instead, it points to an index
+      // in the strtab with a \0 to make iterating through the symtab easier.
+    { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1,
+    },
+    { st_name: 0,   // starting index of the name in libdl_info.strtab
+      st_value: (Elf32_Addr) &dlopen,
+      st_info: STB_GLOBAL << 4,
+      st_shndx: 1,
+    },
+    { st_name: 7,
+      st_value: (Elf32_Addr) &dlclose,
+      st_info: STB_GLOBAL << 4,
+      st_shndx: 1,
+    },
+    { st_name: 15,
+      st_value: (Elf32_Addr) &dlsym,
+      st_info: STB_GLOBAL << 4,
+      st_shndx: 1,
+    },
+    { st_name: 21,
+      st_value: (Elf32_Addr) &dlerror,
+      st_info: STB_GLOBAL << 4,
+      st_shndx: 1,
+    },
+#ifdef ANDROID_ARM_LINKER
+    { st_name: 29,
+      st_value: (Elf32_Addr) &dl_unwind_find_exidx,
+      st_info: STB_GLOBAL << 4,
+      st_shndx: 1,
+    },
+#elif defined(ANDROID_X86_LINKER)
+    { st_name: 29,
+      st_value: (Elf32_Addr) &dl_iterate_phdr,
+      st_info: STB_GLOBAL << 4,
+      st_shndx: 1,
+    },
+#endif
+};
+
+/* Fake out a hash table with a single bucket.
+ * A search of the hash table will look through
+ * libdl_symtab starting with index [1], then
+ * use libdl_chains to find the next index to
+ * look at.  libdl_chains should be set up to
+ * walk through every element in libdl_symtab,
+ * and then end with 0 (sentinel value).
+ *
+ * I.e., libdl_chains should look like
+ * { 0, 2, 3, ... N, 0 } where N is the number
+ * of actual symbols, or nelems(libdl_symtab)-1
+ * (since the first element of libdl_symtab is not
+ * a real symbol).
+ *
+ * (see _elf_lookup())
+ *
+ * Note that adding any new symbols here requires
+ * stubbing them out in libdl.
+ */
+static unsigned libdl_buckets[1] = { 1 };
+static unsigned libdl_chains[6] = { 0, 2, 3, 4, 5, 0 };
+
+soinfo libdl_info = {
+    name: "libdl.so",
+    flags: FLAG_LINKED,
+
+    strtab: ANDROID_LIBDL_STRTAB,
+    symtab: libdl_symtab,
+
+    nbucket: 1,
+    nchain: 6,
+    bucket: libdl_buckets,
+    chain: libdl_chains,
+};
+