dlfcn.c revision 5c734644eebf8d01be1e86cbe20a111a5c5a2738
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16#include <dlfcn.h> 17#include <pthread.h> 18#include <stdio.h> 19#include "linker.h" 20#include "linker_format.h" 21 22/* This file hijacks the symbols stubbed out in libdl.so. */ 23 24#define DL_SUCCESS 0 25#define DL_ERR_CANNOT_LOAD_LIBRARY 1 26#define DL_ERR_INVALID_LIBRARY_HANDLE 2 27#define DL_ERR_BAD_SYMBOL_NAME 3 28#define DL_ERR_SYMBOL_NOT_FOUND 4 29#define DL_ERR_SYMBOL_NOT_GLOBAL 5 30 31static char dl_err_buf[1024]; 32static const char *dl_err_str; 33 34static const char *dl_errors[] = { 35 [DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library", 36 [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle", 37 [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name", 38 [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found", 39 [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global", 40}; 41 42#define likely(expr) __builtin_expect (expr, 1) 43#define unlikely(expr) __builtin_expect (expr, 0) 44 45static pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER; 46 47static void set_dlerror(int err) 48{ 49 format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err], 50 linker_get_error()); 51 dl_err_str = (const char *)&dl_err_buf[0]; 52}; 53 54void *dlopen(const char *filename, int flag) 55{ 56 soinfo *ret; 57 58 pthread_mutex_lock(&dl_lock); 59 ret = find_library(filename); 60 if (unlikely(ret == NULL)) { 61 set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY); 62 } else { 63 ret->refcount++; 64 } 65 pthread_mutex_unlock(&dl_lock); 66 return ret; 67} 68 69const char *dlerror(void) 70{ 71 const char *tmp = dl_err_str; 72 dl_err_str = NULL; 73 return (const char *)tmp; 74} 75 76void *dlsym(void *handle, const char *symbol) 77{ 78 soinfo *found; 79 Elf32_Sym *sym; 80 unsigned bind; 81 82 pthread_mutex_lock(&dl_lock); 83 84 if(unlikely(handle == 0)) { 85 set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE); 86 goto err; 87 } 88 if(unlikely(symbol == 0)) { 89 set_dlerror(DL_ERR_BAD_SYMBOL_NAME); 90 goto err; 91 } 92 93 if(handle == RTLD_DEFAULT) { 94 sym = lookup(symbol, &found); 95 } else if(handle == RTLD_NEXT) { 96 sym = lookup(symbol, &found); 97 } else { 98 found = (soinfo*)handle; 99 sym = lookup_in_library(found, symbol); 100 } 101 102 if(likely(sym != 0)) { 103 bind = ELF32_ST_BIND(sym->st_info); 104 105 if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { 106 unsigned ret = sym->st_value + found->base; 107 pthread_mutex_unlock(&dl_lock); 108 return (void*)ret; 109 } 110 111 set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL); 112 } 113 else 114 set_dlerror(DL_ERR_SYMBOL_NOT_FOUND); 115 116err: 117 pthread_mutex_unlock(&dl_lock); 118 return 0; 119} 120 121int dlclose(void *handle) 122{ 123 pthread_mutex_lock(&dl_lock); 124 (void)unload_library((soinfo*)handle); 125 pthread_mutex_unlock(&dl_lock); 126 return 0; 127} 128 129#if defined(ANDROID_ARM_LINKER) 130// 0000000 00011111 111112 22222222 233333333334444444444 131// 0123456 78901234 567890 12345678 901234567890123456789 132#define ANDROID_LIBDL_STRTAB \ 133 "dlopen\0dlclose\0dlsym\0dlerror\0dl_unwind_find_exidx\0" 134 135#elif defined(ANDROID_X86_LINKER) 136// 0000000 00011111 111112 22222222 2333333333344444 137// 0123456 78901234 567890 12345678 9012345678901234 138#define ANDROID_LIBDL_STRTAB \ 139 "dlopen\0dlclose\0dlsym\0dlerror\0dl_iterate_phdr\0" 140 141#elif defined(ANDROID_SH_LINKER) 142// 0000000 00011111 111112 22222222 2333333333344444 143// 0123456 78901234 567890 12345678 9012345678901234 144#define ANDROID_LIBDL_STRTAB \ 145 "dlopen\0dlclose\0dlsym\0dlerror\0dl_iterate_phdr\0" 146 147#else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */ 148#error Unsupported architecture. Only ARM and x86 are presently supported. 149#endif 150 151 152static Elf32_Sym libdl_symtab[] = { 153 // total length of libdl_info.strtab, including trailing 0 154 // This is actually the the STH_UNDEF entry. Technically, it's 155 // supposed to have st_name == 0, but instead, it points to an index 156 // in the strtab with a \0 to make iterating through the symtab easier. 157 { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1, 158 }, 159 { st_name: 0, // starting index of the name in libdl_info.strtab 160 st_value: (Elf32_Addr) &dlopen, 161 st_info: STB_GLOBAL << 4, 162 st_shndx: 1, 163 }, 164 { st_name: 7, 165 st_value: (Elf32_Addr) &dlclose, 166 st_info: STB_GLOBAL << 4, 167 st_shndx: 1, 168 }, 169 { st_name: 15, 170 st_value: (Elf32_Addr) &dlsym, 171 st_info: STB_GLOBAL << 4, 172 st_shndx: 1, 173 }, 174 { st_name: 21, 175 st_value: (Elf32_Addr) &dlerror, 176 st_info: STB_GLOBAL << 4, 177 st_shndx: 1, 178 }, 179#ifdef ANDROID_ARM_LINKER 180 { st_name: 29, 181 st_value: (Elf32_Addr) &dl_unwind_find_exidx, 182 st_info: STB_GLOBAL << 4, 183 st_shndx: 1, 184 }, 185#elif defined(ANDROID_X86_LINKER) 186 { st_name: 29, 187 st_value: (Elf32_Addr) &dl_iterate_phdr, 188 st_info: STB_GLOBAL << 4, 189 st_shndx: 1, 190 }, 191#elif defined(ANDROID_SH_LINKER) 192 { st_name: 29, 193 st_value: (Elf32_Addr) &dl_iterate_phdr, 194 st_info: STB_GLOBAL << 4, 195 st_shndx: 1, 196 }, 197#endif 198}; 199 200/* Fake out a hash table with a single bucket. 201 * A search of the hash table will look through 202 * libdl_symtab starting with index [1], then 203 * use libdl_chains to find the next index to 204 * look at. libdl_chains should be set up to 205 * walk through every element in libdl_symtab, 206 * and then end with 0 (sentinel value). 207 * 208 * I.e., libdl_chains should look like 209 * { 0, 2, 3, ... N, 0 } where N is the number 210 * of actual symbols, or nelems(libdl_symtab)-1 211 * (since the first element of libdl_symtab is not 212 * a real symbol). 213 * 214 * (see _elf_lookup()) 215 * 216 * Note that adding any new symbols here requires 217 * stubbing them out in libdl. 218 */ 219static unsigned libdl_buckets[1] = { 1 }; 220static unsigned libdl_chains[6] = { 0, 2, 3, 4, 5, 0 }; 221 222soinfo libdl_info = { 223 name: "libdl.so", 224 flags: FLAG_LINKED, 225 226 strtab: ANDROID_LIBDL_STRTAB, 227 symtab: libdl_symtab, 228 229 nbucket: 1, 230 nchain: 6, 231 bucket: libdl_buckets, 232 chain: libdl_chains, 233}; 234 235