|
@@ -1,12 +1,12 @@
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+ * Program to load an ELF binary on a linux system, and run it
|
|
|
* after resolving ELF shared library symbols
|
|
|
*
|
|
|
- * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
|
|
|
+ * Copyright (C) 2004 by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
|
|
|
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codpoet.org>
|
|
|
+ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
|
|
|
* David Engel, Hongjiu Lu and Mitch D'Souza
|
|
|
- * Copyright (C) 2001-2002, Erik Andersen
|
|
|
- *
|
|
|
- * All rights reserved.
|
|
|
*
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
* modification, are permitted provided that the following conditions
|
|
@@ -35,10 +35,9 @@
|
|
|
|
|
|
|
|
|
* This is the start of the linked list that describes all of the files present
|
|
|
- * in the system with pointers to all of the symbol, string, and hash tables,
|
|
|
+ * in the system with pointers to all of the symbol, string, and hash tables,
|
|
|
* as well as all of the other good stuff in the binary.
|
|
|
*/
|
|
|
-
|
|
|
struct elf_resolve *_dl_loaded_modules = NULL;
|
|
|
|
|
|
|
|
@@ -55,12 +54,9 @@ struct dyn_elf *_dl_symbol_tables = NULL;
|
|
|
struct dyn_elf *_dl_handles = NULL;
|
|
|
|
|
|
|
|
|
-
|
|
|
- * This is the hash function that is used by the ELF linker to generate
|
|
|
- * the hash table that each executable and library is required to
|
|
|
- * have. We need it to decode the hash table.
|
|
|
- */
|
|
|
-
|
|
|
+
|
|
|
+ * hash table that each executable and library is required to have. We need
|
|
|
+ * it to decode the hash table. */
|
|
|
unsigned long _dl_elf_hash(const char *name)
|
|
|
{
|
|
|
unsigned long hash = 0;
|
|
@@ -75,9 +71,7 @@ unsigned long _dl_elf_hash(const char *name)
|
|
|
return hash;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- * Check to see if a library has already been added to the hash chain.
|
|
|
- */
|
|
|
+
|
|
|
struct elf_resolve *_dl_check_hashed_files(const char *libname)
|
|
|
{
|
|
|
struct elf_resolve *tpnt;
|
|
@@ -97,9 +91,8 @@ struct elf_resolve *_dl_check_hashed_files(const char *libname)
|
|
|
* We add the relevant info to the symbol chain, so that we can resolve all
|
|
|
* externals properly.
|
|
|
*/
|
|
|
-
|
|
|
-struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
|
|
|
- char *loadaddr, unsigned long *dynamic_info, unsigned long dynamic_addr,
|
|
|
+struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
|
|
|
+ char *loadaddr, unsigned long *dynamic_info, unsigned long dynamic_addr,
|
|
|
unsigned long dynamic_size)
|
|
|
{
|
|
|
unsigned long *hash_addr;
|
|
@@ -107,8 +100,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
|
|
|
int i;
|
|
|
|
|
|
if (!_dl_loaded_modules) {
|
|
|
- tpnt = _dl_loaded_modules =
|
|
|
- (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
|
|
|
+ tpnt = _dl_loaded_modules = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
|
|
|
_dl_memset(tpnt, 0, sizeof(struct elf_resolve));
|
|
|
} else {
|
|
|
tpnt = _dl_loaded_modules;
|
|
@@ -161,21 +153,18 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
|
|
|
* This function resolves externals, and this is either called when we process
|
|
|
* relocations or when we call an entry in the PLT table for the first time.
|
|
|
*/
|
|
|
-
|
|
|
-char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
|
|
|
+char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
|
|
|
struct elf_resolve *f_tpnt, enum caller_type caller_type)
|
|
|
{
|
|
|
struct elf_resolve *tpnt;
|
|
|
int si;
|
|
|
- char *pnt;
|
|
|
int pass;
|
|
|
char *strtab;
|
|
|
Elf32_Sym *symtab;
|
|
|
unsigned long elf_hash_number, hn;
|
|
|
char *weak_result;
|
|
|
- struct elf_resolve *first_def;
|
|
|
struct dyn_elf *rpnt, first;
|
|
|
- char *data_result = 0;
|
|
|
+ const ElfW(Sym) *sym;
|
|
|
|
|
|
weak_result = 0;
|
|
|
elf_hash_number = _dl_elf_hash(name);
|
|
@@ -185,7 +174,7 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
|
|
|
that any shared library data symbols referenced in the executable
|
|
|
will be seen at the same address by the executable, shared libraries
|
|
|
and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
|
|
|
- if (_dl_symbol_tables && !caller_type && rpnt1) {
|
|
|
+ if (_dl_symbol_tables && rpnt1) {
|
|
|
first = (*_dl_symbol_tables);
|
|
|
first.next = rpnt1;
|
|
|
rpnt1 = (&first);
|
|
@@ -222,24 +211,16 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
|
|
|
if (pass != 0) {
|
|
|
if (rpnt1 == NULL)
|
|
|
break;
|
|
|
- if ((rpnt1->flags & RTLD_GLOBAL) == 0)
|
|
|
- continue;
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
for (rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); rpnt; rpnt = rpnt->next) {
|
|
|
tpnt = rpnt->dyn;
|
|
|
|
|
|
-
|
|
|
- * The idea here is that if we are using dlsym, we want to
|
|
|
- * first search the entire chain loaded from dlopen, and
|
|
|
- * return a result from that if we found anything. If this
|
|
|
- * fails, then we continue the search into the stuff loaded
|
|
|
- * when the image was activated. For normal lookups, we start
|
|
|
- * with rpnt == NULL, so we should never hit this.
|
|
|
- */
|
|
|
- if (tpnt->libtype == elf_executable && weak_result != 0) {
|
|
|
- break;
|
|
|
- }
|
|
|
+
|
|
|
+ if (tpnt->libtype == elf_executable && caller_type == copyrel)
|
|
|
+ continue;
|
|
|
|
|
|
|
|
|
* Avoid calling .urem here.
|
|
@@ -247,81 +228,35 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
|
|
|
do_rem(hn, elf_hash_number, tpnt->nbucket);
|
|
|
symtab = (Elf32_Sym *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
|
|
|
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
|
|
|
-
|
|
|
- * This crap is required because the first instance of a
|
|
|
- * symbol on the chain will be used for all symbol references.
|
|
|
- * Thus this instance must be resolved to an address that
|
|
|
- * contains the actual function,
|
|
|
- */
|
|
|
-
|
|
|
- first_def = NULL;
|
|
|
-
|
|
|
- for (si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]) {
|
|
|
- pnt = strtab + symtab[si].st_name;
|
|
|
-
|
|
|
- if (_dl_strcmp(pnt, name) == 0 &&
|
|
|
- symtab[si].st_value != 0)
|
|
|
- {
|
|
|
- if ((ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
|
|
|
- ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE ||
|
|
|
- ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
|
|
|
- symtab[si].st_shndx != SHN_UNDEF) {
|
|
|
-
|
|
|
-
|
|
|
- * actually defined.
|
|
|
- */
|
|
|
-
|
|
|
- if (f_tpnt) {
|
|
|
- if (!first_def)
|
|
|
- first_def = tpnt;
|
|
|
- if (first_def == f_tpnt
|
|
|
- && symtab[si].st_shndx == 0)
|
|
|
- continue;
|
|
|
- }
|
|
|
|
|
|
- switch (ELF32_ST_BIND(symtab[si].st_info)) {
|
|
|
- case STB_GLOBAL:
|
|
|
- if (tpnt->libtype != elf_executable &&
|
|
|
- ELF32_ST_TYPE(symtab[si].st_info)
|
|
|
- == STT_NOTYPE)
|
|
|
- {
|
|
|
- data_result = (char *)tpnt->loadaddr +
|
|
|
- symtab[si].st_value;
|
|
|
- break;
|
|
|
- } else
|
|
|
- return (char*)tpnt->loadaddr + symtab[si].st_value;
|
|
|
- case STB_WEAK:
|
|
|
- if (!weak_result)
|
|
|
- weak_result = (char *)tpnt->loadaddr + symtab[si].st_value;
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-#ifndef __mips__
|
|
|
-
|
|
|
- * References to the address of a function from an executable file and
|
|
|
- * the shared objects associated with it might not resolve to the same
|
|
|
- * value. To allow comparisons of function addresses we must resolve
|
|
|
- * to the address of the plt entry of the executable instead of the
|
|
|
- * real function address.
|
|
|
- * see "TIS ELF Specification Version 1.2, Book 3, A-11 (Function
|
|
|
- * Adresses)
|
|
|
- */
|
|
|
- if (resolver != caller_type &&
|
|
|
- NULL==f_tpnt &&
|
|
|
- tpnt->libtype == elf_executable &&
|
|
|
- ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC &&
|
|
|
- symtab[si].st_shndx == SHN_UNDEF)
|
|
|
- {
|
|
|
- return (char*)symtab[si].st_value;
|
|
|
- }
|
|
|
+ for (si = tpnt->elf_buckets[hn]; si != STN_UNDEF; si = tpnt->chains[si]) {
|
|
|
+ sym = &symtab[si];
|
|
|
+
|
|
|
+ if (sym->st_value == 0)
|
|
|
+ continue;
|
|
|
+ if (ELF32_ST_TYPE(sym->st_info) > STT_FUNC)
|
|
|
+ continue;
|
|
|
+ if (sym->st_shndx == SHN_UNDEF && caller_type != copyrel)
|
|
|
+ continue;
|
|
|
+ if (_dl_strcmp(strtab + sym->st_name, name) != 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ switch (ELF32_ST_BIND(sym->st_info)) {
|
|
|
+ case STB_WEAK:
|
|
|
+
|
|
|
+
|
|
|
+#if 1
|
|
|
+ if (!weak_result)
|
|
|
+ weak_result = (char *)tpnt->loadaddr + sym->st_value;
|
|
|
+ break;
|
|
|
#endif
|
|
|
+ case STB_GLOBAL:
|
|
|
+ return (char*)tpnt->loadaddr + sym->st_value;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- if (data_result)
|
|
|
- return data_result;
|
|
|
return weak_result;
|
|
|
}
|