1 /* vi: set sw=4 ts=4: */
3 * Program to load an ELF binary on a linux system, and run it
4 * after resolving ELF shared library symbols
6 * Copyright (C) 2004 by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
7 * Copyright (C) 2000-2004 by Erik Andersen <andersen@codpoet.org>
8 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
9 * David Engel, Hongjiu Lu and Mitch D'Souza
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. The name of the above contributors may not be
17 * used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 /* Various symbol table handling functions, including symbol lookup */
37 * This is the start of the linked list that describes all of the files present
38 * in the system with pointers to all of the symbol, string, and hash tables,
39 * as well as all of the other good stuff in the binary.
41 struct elf_resolve *_dl_loaded_modules = NULL;
44 * This is the list of modules that are loaded when the image is first
45 * started. As we add more via dlopen, they get added into other
48 struct dyn_elf *_dl_symbol_tables = NULL;
51 * This is the list of modules that are loaded via dlopen. We may need
52 * to search these for RTLD_GLOBAL files.
54 struct dyn_elf *_dl_handles = NULL;
57 /* This is the hash function that is used by the ELF linker to generate the
58 * hash table that each executable and library is required to have. We need
59 * it to decode the hash table. */
60 unsigned long _dl_elf_hash(const unsigned char *name)
62 unsigned long hash = 0;
66 hash = (hash << 4) + *name++;
67 if ((tmp = hash & 0xf0000000))
74 /* Check to see if a library has already been added to the hash chain. */
75 struct elf_resolve *_dl_check_hashed_files(const char *libname)
77 struct elf_resolve *tpnt;
78 int len = _dl_strlen(libname);
80 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
81 if (_dl_strncmp(tpnt->libname, libname, len) == 0 &&
82 (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.'))
90 * We call this function when we have just read an ELF library or executable.
91 * We add the relevant info to the symbol chain, so that we can resolve all
94 struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
95 char *loadaddr, unsigned long *dynamic_info, unsigned long dynamic_addr,
96 unsigned long dynamic_size)
98 unsigned long *hash_addr;
99 struct elf_resolve *tpnt;
102 if (!_dl_loaded_modules) {
103 tpnt = _dl_loaded_modules = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
104 _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
106 tpnt = _dl_loaded_modules;
109 tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
110 _dl_memset(tpnt->next, 0, sizeof(struct elf_resolve));
111 tpnt->next->prev = tpnt;
117 tpnt->libname = _dl_strdup(libname);
118 tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
119 tpnt->libtype = loaded_file;
121 if (dynamic_info[DT_HASH] != 0) {
122 hash_addr = (unsigned long *) (intptr_t)(dynamic_info[DT_HASH] + loadaddr);
123 tpnt->nbucket = *hash_addr++;
124 tpnt->nchain = *hash_addr++;
125 tpnt->elf_buckets = hash_addr;
126 hash_addr += tpnt->nbucket;
127 tpnt->chains = hash_addr;
129 tpnt->loadaddr = (ElfW(Addr))loadaddr;
130 for (i = 0; i < DYNAMIC_SIZE; i++)
131 tpnt->dynamic_info[i] = dynamic_info[i];
137 * This function resolves externals, and this is either called when we process
138 * relocations or when we call an entry in the PLT table for the first time.
140 char *_dl_find_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve *mytpnt, int type_class)
142 struct elf_resolve *tpnt;
146 unsigned long elf_hash_number, hn;
147 const ElfW(Sym) *sym;
148 char *weak_result = NULL;
150 elf_hash_number = _dl_elf_hash(name);
152 for (; rpnt; rpnt = rpnt->next) {
155 if (!(tpnt->rtld_flags & RTLD_GLOBAL) && mytpnt) {
159 struct init_fini_list *tmp;
161 for (tmp = mytpnt->rtld_local; tmp; tmp = tmp->next) {
162 if (tmp->tpnt == tpnt)
169 /* Don't search the executable when resolving a copy reloc. */
170 if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
173 /* Avoid calling .urem here. */
174 do_rem(hn, elf_hash_number, tpnt->nbucket);
175 symtab = (Elf32_Sym *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
176 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
178 for (si = tpnt->elf_buckets[hn]; si != STN_UNDEF; si = tpnt->chains[si]) {
181 if (type_class & (sym->st_shndx == SHN_UNDEF))
183 if (_dl_strcmp(strtab + sym->st_name, name) != 0)
185 if (sym->st_value == 0)
187 if (ELF32_ST_TYPE(sym->st_info) > STT_FUNC)
190 switch (ELF32_ST_BIND(sym->st_info)) {
193 /* Perhaps we should support old style weak symbol handling
194 * per what glibc does when you export LD_DYNAMIC_WEAK */
196 weak_result = (char *)tpnt->loadaddr + sym->st_value;
200 return (char*)tpnt->loadaddr + sym->st_value;
201 default: /* Local symbols not handled here */