summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldso/include/dl-elf.h21
-rw-r--r--ldso/include/dl-hash.h45
-rw-r--r--ldso/include/ldsodefs.h7
-rw-r--r--ldso/ldso/Makefile.in7
-rw-r--r--ldso/ldso/dl-elf.c89
-rw-r--r--ldso/ldso/dl-hash.c325
-rw-r--r--ldso/ldso/dl-tls.c20
-rw-r--r--ldso/ldso/ldso.c30
-rw-r--r--ldso/ldso/sh/dl-debug.h2
-rw-r--r--ldso/ldso/sh/dl-startup.h1
-rw-r--r--ldso/ldso/sh/dl-sysdep.h9
-rw-r--r--ldso/ldso/sh/elfinterp.c48
-rw-r--r--ldso/libdl/Makefile.in4
-rw-r--r--ldso/libdl/libdl.c245
14 files changed, 534 insertions, 319 deletions
diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
index de404aec1..e959de12a 100644
--- a/ldso/include/dl-elf.h
+++ b/ldso/include/dl-elf.h
@@ -84,8 +84,11 @@ extern void _dl_protect_relro (struct elf_resolve *l);
#endif
/* OS and/or GNU dynamic extensions */
-#define OS_NUM 1
-#define DT_RELCONT_IDX DT_NUM
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+# define OS_NUM 2 /* for DT_RELOCCOUNT and DT_GNU_HASH entries */
+#else
+# define OS_NUM 1 /* for DT_RELOCCOUNT entry */
+#endif
#ifndef ARCH_DYNAMIC_INFO
/* define in arch specific code, if needed */
@@ -93,6 +96,13 @@ extern void _dl_protect_relro (struct elf_resolve *l);
#endif
#define DYNAMIC_SIZE (DT_NUM+OS_NUM+ARCH_NUM)
+/* Keep ARCH specific entries into dynamic section at the end of the array */
+#define DT_RELCONT_IDX (DYNAMIC_SIZE - OS_NUM - ARCH_NUM)
+
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+/* GNU hash comes just after the relocation count */
+# define DT_GNU_HASH_IDX (DT_RELCONT_IDX + 1)
+#endif
extern void _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], void *debug_addr, ElfW(Addr) load_off);
@@ -129,6 +139,10 @@ void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], void
if (dpnt->d_tag == DT_FLAGS_1 &&
(dpnt->d_un.d_val & DF_1_NOW))
dynamic_info[DT_BIND_NOW] = 1;
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+ if (dpnt->d_tag == DT_GNU_HASH)
+ dynamic_info[DT_GNU_HASH_IDX] = dpnt->d_un.d_ptr;
+#endif
}
#ifdef ARCH_DYNAMIC_INFO
else {
@@ -147,6 +161,9 @@ void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], void
ADJUST_DYN_INFO(DT_SYMTAB, load_off);
ADJUST_DYN_INFO(DT_RELOC_TABLE_ADDR, load_off);
ADJUST_DYN_INFO(DT_JMPREL, load_off);
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+ ADJUST_DYN_INFO(DT_GNU_HASH_IDX, load_off);
+#endif
#undef ADJUST_DYN_INFO
}
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index f496e580d..fb75c8611 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -65,14 +65,39 @@ struct elf_resolve {
unsigned short int init_flag;
unsigned long rtld_flags; /* RTLD_GLOBAL, RTLD_NOW etc. */
Elf_Symndx nbucket;
+
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+ /* Data needed to support GNU hash style */
+ Elf32_Word l_gnu_bitmask_idxbits;
+ Elf32_Word l_gnu_shift;
+ const ElfW(Addr) *l_gnu_bitmask;
+
+ union
+ {
+ const Elf32_Word *l_gnu_chain_zero;
+ const Elf_Symndx *elf_buckets;
+ };
+#else
Elf_Symndx *elf_buckets;
+#endif
+
struct init_fini_list *init_fini;
struct init_fini_list *rtld_local; /* keep tack of RTLD_LOCAL libs in same group */
/*
* These are only used with ELF style shared libraries
*/
Elf_Symndx nchain;
+
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+ union
+ {
+ const Elf32_Word *l_gnu_buckets;
+ const Elf_Symndx *chains;
+ };
+#else
Elf_Symndx *chains;
+#endif
+
unsigned long dynamic_info[DYNAMIC_SIZE];
unsigned long n_phent;
@@ -105,11 +130,23 @@ extern 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);
-extern char * _dl_find_hash(const char * name, struct dyn_elf * rpnt1,
- struct elf_resolve *mytpnt, int type_class);
+extern char * _dl_lookup_hash(const char * name, struct dyn_elf * rpnt1,
+ struct elf_resolve *mytpnt, int type_class
+ #if USE_TLS
+ ,struct elf_resolve **tls_tpnt
+ #endif
+ );
+
+static __always_inline char *_dl_find_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve *mytpnt,
+ int type_class, struct elf_resolve **tls_tpnt)
+{
+#ifdef USE_TLS
+ return _dl_lookup_hash(name, rpnt, mytpnt, type_class, tls_tpnt);
+#else
+ return _dl_lookup_hash(name, rpnt, mytpnt, type_class);
+#endif
+}
-extern char * _dl_find_hash2(const char * name, struct dyn_elf * rpnt1,
- struct elf_resolve *mytpnt, int type_class, ElfW(Sym) **sym_tls, struct elf_resolve **tpnt_tls);
extern int _dl_linux_dynamic_link(void);
diff --git a/ldso/include/ldsodefs.h b/ldso/include/ldsodefs.h
index edc7efee3..bd3b02d47 100644
--- a/ldso/include/ldsodefs.h
+++ b/ldso/include/ldsodefs.h
@@ -63,6 +63,13 @@ extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
extern void _dl_allocate_static_tls (struct link_map *map)
internal_function attribute_hidden;
+/* Taken from glibc/elf/dl-reloc.c */
+#define CHECK_STATIC_TLS(sym_map) \
+ do { \
+ if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \
+ _dl_allocate_static_tls (sym_map); \
+ } while (0)
+
/* These are internal entry points to the two halves of _dl_allocate_tls,
only used within rtld.c itself at startup time. */
extern void *_dl_allocate_tls_storage (void)
diff --git a/ldso/ldso/Makefile.in b/ldso/ldso/Makefile.in
index a92734817..5c58afce4 100644
--- a/ldso/ldso/Makefile.in
+++ b/ldso/ldso/Makefile.in
@@ -13,6 +13,13 @@ CFLAGS-ldso += -fno-omit-frame-pointer
CFLAGS-ldso += -I$(top_srcdir)ldso/ldso/$(TARGET_ARCH) -I$(top_srcdir)ldso/include -I$(top_srcdir)ldso/ldso
CFLAGS-ldso += -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" -DUCLIBC_LDSO=\"$(UCLIBC_LDSO)\"
+ifeq ($(DODEBUG),y)
+# Not really much point in including debugging info, since gdb
+# can't really debug ldso, since gdb requires help from ldso to
+# debug things....
+CFLAGS-ldso += -Os -g
+endif
+
CFLAGS-ldso/ldso/$(TARGET_ARCH)/ := $(CFLAGS-ldso)
CFLAGS-ldso.c := -DLDSO_ELFINTERP=\"$(TARGET_ARCH)/elfinterp.c\"
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 866b2560a..bf97ede7c 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -136,26 +136,13 @@ static struct elf_resolve *
search_for_named_library(const char *name, int secure, const char *path_list,
struct dyn_elf **rpnt)
{
-#ifdef USE_TLS
- char *path, *path_n;
- char mylibname[2050];
-#else
char *path, *path_n, *mylibname;
-#endif
struct elf_resolve *tpnt;
int done;
if (path_list==NULL)
return NULL;
-#ifdef USE_TLS
- /* We need a writable copy of this string */
- path = _dl_strdup(path_list);
- if (!path) {
- _dl_dprintf(2, "Out of memory!\n");
- _dl_exit(0);
- }
-#else
/* We need a writable copy of this string, but we don't
* need this allocated permanently since we don't want
* to leak memory, so use alloca to put path on the stack */
@@ -166,7 +153,6 @@ search_for_named_library(const char *name, int secure, const char *path_list,
mylibname = alloca(2050);
_dl_memcpy(path, path_list, done+1);
-#endif
/* Unlike ldd.c, don't bother to eliminate double //s */
@@ -347,6 +333,9 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
ElfW(Dyn) *dpnt;
struct elf_resolve *tpnt;
ElfW(Phdr) *ppnt;
+#if USE_TLS
+ ElfW(Phdr) *tlsppnt = NULL;
+#endif
char *status, *header;
unsigned long dynamic_info[DYNAMIC_SIZE];
unsigned long *lpnt;
@@ -450,6 +439,29 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
maxvma = ppnt->p_vaddr + ppnt->p_memsz;
}
}
+ if (ppnt->p_type == PT_TLS)
+ {
+#if USE_TLS
+ if (ppnt->p_memsz == 0)
+ /* Nothing to do for an empty segment. */
+ continue;
+ else
+ /* Save for after 'tpnt' is actually allocated. */
+ tlsppnt = ppnt;
+#else
+ /*
+ * Yup, the user was an idiot and tried to sneak in a library with
+ * TLS in it and we don't support it. Let's fall on our own sword
+ * and scream at the luser while we die.
+ */
+ _dl_dprintf(2, "%s: '%s' library contains unsupported TLS\n",
+ _dl_progname, libname);
+ _dl_internal_error_number = LD_ERROR_TLS_FAILED;
+ _dl_close(infile);
+ _dl_munmap(header, _dl_pagesize);
+ return NULL;
+#endif
+ }
ppnt++;
}
@@ -602,39 +614,33 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
tpnt->n_phent = epnt->e_phnum;
#if USE_TLS
- for (i = 0, ppnt = tpnt->ppnt; i < tpnt->n_phent; i++) {
- if (ppnt->p_type == PT_TLS)
- {
- if(ppnt->p_memsz == 0)
- break;
+ if (tlsppnt)
+ {
_dl_debug_early("Found TLS header for %s\n", libname);
#if NO_TLS_OFFSET != 0
tpnt->l_tls_offset = NO_TLS_OFFSET;
#endif
- tpnt->l_tls_blocksize = ppnt->p_memsz;
- tpnt->l_tls_align = ppnt->p_align;
- if (ppnt->p_align == 0)
+ tpnt->l_tls_blocksize = tlsppnt->p_memsz;
+ tpnt->l_tls_align = tlsppnt->p_align;
+ if (tlsppnt->p_align == 0)
tpnt->l_tls_firstbyte_offset = 0;
else
- tpnt->l_tls_firstbyte_offset = ppnt->p_vaddr &
- (ppnt->p_align - 1);
- tpnt->l_tls_initimage_size = ppnt->p_filesz;
- tpnt->l_tls_initimage = (void *) ppnt->p_vaddr;
-
+ tpnt->l_tls_firstbyte_offset = tlsppnt->p_vaddr &
+ (tlsppnt->p_align - 1);
+ tpnt->l_tls_initimage_size = tlsppnt->p_filesz;
+ tpnt->l_tls_initimage = (void *) tlsppnt->p_vaddr;
+
/* Assign the next available module ID. */
tpnt->l_tls_modid = _dl_next_tls_modid ();
-
+
/* We know the load address, so add it to the offset. */
if (tpnt->l_tls_initimage != NULL)
{
unsigned int tmp = (unsigned int) tpnt->l_tls_initimage;
- tpnt->l_tls_initimage = (char *) ppnt->p_vaddr + tpnt->loadaddr;
+ tpnt->l_tls_initimage = (char *) tlsppnt->p_vaddr + tpnt->loadaddr;
_dl_debug_early("Relocated TLS initial image from %x to %x (size = %x)\n", tmp, tpnt->l_tls_initimage, tpnt->l_tls_initimage_size);
tmp = 0;
}
- break;
- }
- ppnt++;
}
#endif
@@ -646,9 +652,19 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
_dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
(*rpnt)->next->prev = (*rpnt);
*rpnt = (*rpnt)->next;
- (*rpnt)->dyn = tpnt;
- tpnt->symbol_scope = _dl_symbol_tables;
}
+#ifndef SHARED
+ /* When statically linked, the first time we dlopen a DSO
+ * the *rpnt is NULL, so we need to allocate memory for it,
+ * and initialize the _dl_symbol_table.
+ */
+ else {
+ *rpnt = _dl_symbol_tables = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+ _dl_memset(*rpnt, 0, sizeof(struct dyn_elf));
+ }
+#endif
+ (*rpnt)->dyn = tpnt;
+ tpnt->symbol_scope = _dl_symbol_tables;
tpnt->usage_count++;
tpnt->libtype = elf_lib;
@@ -737,12 +753,15 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
tpnt->init_flag |= JMP_RELOCS_DONE;
}
+#if 0
+/* _dl_add_to_slotinfo is called by init_tls() for initial DSO
+ or by dlopen() for dynamically loaded DSO. */
#if USE_TLS
/* Add object to slot information data if necessasy. */
if (tpnt->l_tls_blocksize != 0 && tls_init_tp_called)
_dl_add_to_slotinfo ((struct link_map *) tpnt);
#endif
-
+#endif
return goof;
}
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index e692fb6ab..971b1842c 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -53,21 +53,24 @@ struct dyn_elf *_dl_symbol_tables = NULL;
*/
struct dyn_elf *_dl_handles = NULL;
-#if USE_TLS
-/*
- * These are only used when doing TLS relocations. They are referenced from
- * other parts of the linker and from 'libdl.so'. This allows preservation
- * of the '_dl_find_hash' interface.
- */
-ElfW(Sym) *_dl_tls_reloc_sym = NULL;
-struct elf_resolve *_dl_tls_reloc_tpnt = NULL;
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+/* This is the new hash function that is used by the ELF linker to generate the
+ * GNU hash table that each executable and library will have if --hash-style=[gnu,both]
+ * is passed to the linker. We need it to decode the GNU hash table. */
+static inline Elf_Symndx _dl_gnu_hash (const unsigned char *name)
+{
+ unsigned long h = 5381;
+ unsigned char c;
+ for (c = *name; c != '\0'; c = *++name)
+ h = h * 33 + c;
+ return h & 0xffffffff;
+}
#endif
-
/* 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. */
-static inline Elf_Symndx _dl_elf_hash(const char *name)
+static inline Elf_Symndx _dl_elf_hash(const unsigned char *name)
{
unsigned long hash=0;
unsigned long tmp;
@@ -118,6 +121,29 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
tpnt->libname = _dl_strdup(libname);
tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
tpnt->libtype = loaded_file;
+
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+ if (dynamic_info[DT_GNU_HASH_IDX] != 0) {
+
+ Elf32_Word *hash32 = (Elf_Symndx*)dynamic_info[DT_GNU_HASH_IDX];
+
+ tpnt->nbucket = *hash32++;
+ Elf32_Word symbias = *hash32++;
+ Elf32_Word bitmask_nwords = *hash32++;
+ /* Must be a power of two. */
+ _dl_assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
+ tpnt->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
+ tpnt->l_gnu_shift = *hash32++;
+
+ tpnt->l_gnu_bitmask = (ElfW(Addr) *) hash32;
+ hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;
+
+ tpnt->l_gnu_buckets = hash32;
+ hash32 += tpnt->nbucket;
+ tpnt->l_gnu_chain_zero = hash32 - symbias;
+ } else
+ /* Fall using old SysV hash table if GNU hash is not present */
+#endif
if (dynamic_info[DT_HASH] != 0) {
hash_addr = (Elf_Symndx*)dynamic_info[DT_HASH];
@@ -134,120 +160,134 @@ 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 *rpnt, struct elf_resolve *mytpnt, int type_class)
-{
- struct elf_resolve *tpnt;
- int si;
- char *strtab;
- ElfW(Sym) *symtab;
- unsigned long elf_hash_number, hn;
- const ElfW(Sym) *sym;
- char *weak_result = NULL;
+/* Routine to check whether the symbol matches. */
+static __attribute_noinline__ const ElfW(Sym) *
+check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int type_class) {
+
#if USE_TLS
- _dl_tls_reloc_sym = NULL;
- _dl_tls_reloc_tpnt = NULL;
+ if((sym->st_value == 0 && (ELF_ST_TYPE(sym->st_info) != STT_TLS))
+ || (type_class & (sym->st_shndx == SHN_UNDEF)))
+ /* No value or undefined symbol itself */
+ return NULL;
+
+ if(ELF_ST_TYPE(sym->st_info) > STT_FUNC
+ && ELF_ST_TYPE(sym->st_info) != STT_COMMON
+ && ELF_ST_TYPE(sym->st_info) != STT_TLS)
+ /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC and STT_COMMON
+ * entries (and STT_TLS if TLS is supported) since these
+ * are no code/data definitions.
+ */
+ return NULL;
+#else
+ if (type_class & (sym->st_shndx == SHN_UNDEF))
+ /* undefined symbol itself */
+ return NULL;
+
+ if (sym->st_value == 0)
+ /* No value */
+ return NULL;
+
+ if (ELF_ST_TYPE(sym->st_info) > STT_FUNC)
+ /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC
+ * entries since these are no code/data definitions.
+ */
+ return NULL;
#endif
+ if (_dl_strcmp(strtab + sym->st_name, undef_name) != 0)
+ return NULL;
- elf_hash_number = _dl_elf_hash(name);
-
- for (; rpnt; rpnt = rpnt->next) {
- tpnt = rpnt->dyn;
-
- if (!(tpnt->rtld_flags & RTLD_GLOBAL) && mytpnt) {
- if (mytpnt == tpnt)
- ;
- else {
- struct init_fini_list *tmp;
-
- for (tmp = mytpnt->rtld_local; tmp; tmp = tmp->next) {
- if (tmp->tpnt == tpnt)
- break;
- }
- if (!tmp)
- continue;
- }
- }
- /* Don't search the executable when resolving a copy reloc. */
- if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
- continue;
+ /* This is the matching symbol */
+ return sym;
+}
- /* Avoid calling .urem here. */
- do_rem(hn, elf_hash_number, tpnt->nbucket);
- symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
- strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
- for (si = tpnt->elf_buckets[hn]; si != STN_UNDEF; si = tpnt->chains[si])
- {
- sym = &symtab[si];
+#ifdef __LDSO_GNU_HASH_SUPPORT__
- if ((sym->st_value == 0
-#if USE_TLS
- && ELF_ST_TYPE(sym->st_info) != STT_TLS
-#endif
- )
- || (type_class & (sym->st_shndx == SHN_UNDEF)))
- continue;
+static __always_inline const ElfW(Sym) *
+_dl_lookup_gnu_hash(struct elf_resolve *tpnt, ElfW(Sym) *symtab, unsigned long hash,
+ const char* undef_name, int type_class) {
- if (ELF_ST_TYPE(sym->st_info) > STT_FUNC
-#if USE_TLS
- && ELF_ST_TYPE(sym->st_info) != STT_TLS
-#endif
- )
- continue;
-
- if (_dl_strcmp(strtab + sym->st_name, name) != 0)
- continue;
-
- switch (ELF_ST_BIND(sym->st_info)) {
- case STB_WEAK:
-#if 0
-/* Perhaps we should support old style weak symbol handling
- * per what glibc does when you export LD_DYNAMIC_WEAK */
- if (!weak_result)
- weak_result = (char *)tpnt->loadaddr + sym->st_value;
- break;
-#endif
- case STB_GLOBAL:
-#if USE_TLS
- /* Update these pointers if we are doing TLS relocations. */
- _dl_tls_reloc_sym = (ElfW(Sym) *) sym;
- _dl_tls_reloc_tpnt = tpnt;
-#endif
- return (char*)tpnt->loadaddr + sym->st_value;
- default: /* Local symbols not handled here */
- break;
- }
+ Elf_Symndx symidx;
+ const ElfW(Sym) *sym;
+ char *strtab;
+
+ const ElfW(Addr) *bitmask = tpnt->l_gnu_bitmask;
+
+ ElfW(Addr) bitmask_word = bitmask[(hash / __ELF_NATIVE_CLASS) & tpnt->l_gnu_bitmask_idxbits];
+
+ unsigned int hashbit1 = hash & (__ELF_NATIVE_CLASS - 1);
+ unsigned int hashbit2 = ((hash >> tpnt->l_gnu_shift) & (__ELF_NATIVE_CLASS - 1));
+
+ _dl_assert (bitmask != NULL);
+
+ if (__builtin_expect ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1, 0)) {
+
+ Elf32_Word bucket = tpnt->l_gnu_buckets[hash % tpnt->nbucket];
+
+ if (bucket != 0) {
+ const Elf32_Word *hasharr = &tpnt->l_gnu_chain_zero[bucket];
+ do {
+ if (((*hasharr ^ hash) >> 1) == 0) {
+ symidx = hasharr - tpnt->l_gnu_chain_zero;
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
+ sym = check_match (&symtab[symidx], strtab, undef_name, type_class);
+ if (sym != NULL)
+ return sym;
+ }
+ } while ((*hasharr++ & 1u) == 0);
}
}
- return weak_result;
+ /* No symbol found. */
+ return NULL;
}
+#endif
+static __always_inline const ElfW(Sym) *
+_dl_lookup_sysv_hash(struct elf_resolve *tpnt, ElfW(Sym) *symtab, unsigned long hash, const char* undef_name, int type_class) {
+ unsigned long hn;
+ char *strtab;
+ const ElfW(Sym) *sym;
+ Elf_Symndx symidx;
+
+ /* Avoid calling .urem here. */
+ do_rem(hn, hash, tpnt->nbucket);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
+
+ _dl_assert(tpnt->elf_buckets != NULL);
+
+ for (symidx = tpnt->elf_buckets[hn]; symidx != STN_UNDEF; symidx = tpnt->chains[symidx]) {
+ sym = check_match (&symtab[symidx], strtab, undef_name, type_class);
+ if (sym != NULL)
+ /* At this point the symbol is that we are looking for */
+ return sym;
+ }
+ /* No symbol found into the current module*/
+ return NULL;
+}
-/* TLS Version
+/*
* 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_hash2(const char *name, struct dyn_elf *rpnt, struct elf_resolve *mytpnt, int type_class, ElfW(Sym) **sym_tls, struct elf_resolve **tpnt_tls)
+char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve *mytpnt, int type_class
+#if USE_TLS
+,struct elf_resolve **tls_tpnt
+#endif
+)
{
- struct elf_resolve *tpnt;
- int si;
- char *strtab;
+ struct elf_resolve *tpnt = NULL;
ElfW(Sym) *symtab;
- unsigned long elf_hash_number, hn;
- const ElfW(Sym) *sym;
- char *weak_result = NULL;
-#if USE_TLS
- _dl_tls_reloc_sym = NULL;
- _dl_tls_reloc_tpnt = NULL;
-#endif
- elf_hash_number = _dl_elf_hash(name);
+ unsigned long elf_hash_number = 0xffffffff;
+ const ElfW(Sym) *sym = NULL;
+
+ char *weak_result = NULL;
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+ unsigned long gnu_hash_number = _dl_gnu_hash((const unsigned char *)name);
+#endif
+
for (; rpnt; rpnt = rpnt->next) {
tpnt = rpnt->dyn;
@@ -268,53 +308,60 @@ char *_dl_find_hash2(const char *name, struct dyn_elf *rpnt, struct elf_resolve
/* Don't search the executable when resolving a copy reloc. */
if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
continue;
-
- /* Avoid calling .urem here. */
- do_rem(hn, elf_hash_number, tpnt->nbucket);
- symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
- strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
-
- for (si = tpnt->elf_buckets[hn]; si != STN_UNDEF; si = tpnt->chains[si])
- {
- sym = &symtab[si];
-
- if ((sym->st_value == 0
-#if USE_TLS
- && ELF_ST_TYPE(sym->st_info) != STT_TLS
-#endif
- )
- || (type_class & (sym->st_shndx == SHN_UNDEF)))
- continue;
-
- if (ELF_ST_TYPE(sym->st_info) > STT_FUNC
-#if USE_TLS
- && ELF_ST_TYPE(sym->st_info) != STT_TLS
+
+ /* If the hash table is empty there is nothing to do here. */
+ if (tpnt->nbucket == 0)
+ continue;
+
+ symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
+
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+ /* Prefer GNU hash style, if any */
+ if(tpnt->l_gnu_bitmask) {
+ if((sym = _dl_lookup_gnu_hash(tpnt, symtab, gnu_hash_number, name, type_class)) != NULL)
+ /* If sym has been found, do not search further */
+ break;
+ } else {
+#endif
+ /* Use the old SysV-style hash table */
+
+ /* Calculate the old sysv hash number only once */
+ if(elf_hash_number == 0xffffffff)
+ elf_hash_number = _dl_elf_hash((const unsigned char *)name);
+
+ if((sym = _dl_lookup_sysv_hash(tpnt, symtab, elf_hash_number, name, type_class)) != NULL )
+ break;
+
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+ }
+#endif
+ } /* end of for (; rpnt; rpnt = rpnt->next) { */
+
+ if(sym) {
+ /* At this point we have found the requested symbol, do binding */
+#if USE_TLS
+ if(ELF_ST_TYPE(sym->st_info) == STT_TLS) {
+ _dl_assert((tls_tpnt != NULL));
+ *tls_tpnt = tpnt;
+
+ return (char*)sym->st_value;
+ }
#endif
- )
- continue;
- if (_dl_strcmp(strtab + sym->st_name, name) != 0)
- continue;
-
- switch (ELF_ST_BIND(sym->st_info)) {
+ switch (ELF_ST_BIND(sym->st_info)) {
case STB_WEAK:
#if 0
-/* Perhaps we should support old style weak symbol handling
- * per what glibc does when you export LD_DYNAMIC_WEAK */
+ /* Perhaps we should support old style weak symbol handling
+ * per what glibc does when you export LD_DYNAMIC_WEAK */
if (!weak_result)
weak_result = (char *)tpnt->loadaddr + sym->st_value;
break;
+
#endif
case STB_GLOBAL:
-#if USE_TLS
- /* Update these pointers if we are doing TLS relocations. */
- *sym_tls = (ElfW(Sym) *) sym;
- *tpnt_tls = tpnt;
-#endif
return (char*)tpnt->loadaddr + sym->st_value;
default: /* Local symbols not handled here */
break;
- }
}
}
return weak_result;
diff --git a/ldso/ldso/dl-tls.c b/ldso/ldso/dl-tls.c
index 0dd270ed7..3e8ad1a18 100644
--- a/ldso/ldso/dl-tls.c
+++ b/ldso/ldso/dl-tls.c
@@ -53,7 +53,7 @@ _dl_calloc (size_t __nmemb, size_t __size)
_dl_exit(1);
}
- if ((result = _dl_malloc(__size)) != NULL) {
+ if ((result = _dl_malloc(size)) != NULL) {
_dl_memset(result, 0, size);
}
@@ -108,13 +108,6 @@ _dl_free (void *__ptr)
/* Value used for dtv entries for which the allocation is delayed. */
#define TLS_DTV_UNALLOCATED ((void *) -1l)
-/* Taken from glibc/elf/dl-reloc.c */
-#define CHECK_STATIC_TLS(sym_map) \
- do { \
- if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \
- _dl_allocate_static_tls (sym_map); \
- } while (0)
-
/*
* We are trying to perform a static TLS relocation in MAP, but it was
* dynamically loaded. This can only work if there is enough surplus in
@@ -386,7 +379,8 @@ _dl_determine_tlsoffset (void)
size_t offset = TLS_TCB_SIZE;
size_t cnt;
- for (cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
+ /* The first slot is never used */
+ for (cnt = 1; slotinfo[cnt].map != NULL; ++cnt)
{
_dl_assert (cnt < _dl_tls_dtv_slotinfo_list->len);
@@ -1001,9 +995,9 @@ init_tls (void)
{
/* This is a module with TLS data. Store the map reference.
The generation counter is zero. */
- slotinfo[i].map = l;
- /* slotinfo[i].gen = 0; */
- ++i;
+
+ /* Skeep slot[0]: it will be never used */
+ slotinfo[++i].map = l;
}
_dl_assert (i == _dl_tls_max_dtv_idx);
@@ -1027,7 +1021,7 @@ init_tls (void)
/* And finally install it for the main thread. If ld.so itself uses
TLS we know the thread pointer was initialized earlier. */
- const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
+ const char *lossage = (char *) TLS_INIT_TP (tcbp, USE___THREAD);
if(__builtin_expect (lossage != NULL, 0)) {
_dl_debug_early("cannot set up thread-local storage: %s\n", lossage);
_dl_exit(30);
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 3991eab04..738b970f4 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -166,6 +166,7 @@ static void __attribute__ ((destructor)) __attribute_used__ _dl_fini(void)
if (tpnt->init_flag & FINI_FUNCS_CALLED)
continue;
tpnt->init_flag |= FINI_FUNCS_CALLED;
+ _dl_run_fini_array(tpnt);
if (tpnt->dynamic_info[DT_FINI]) {
void (*dl_elf_func) (void);
@@ -872,7 +873,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
* ld.so.1, so we have to look up each symbol individually.
*/
- _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", _dl_symbol_tables, NULL, 0);
+ _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", _dl_symbol_tables, NULL, 0, NULL);
if (_dl_envp)
*_dl_envp = (unsigned long) envp;
@@ -898,6 +899,14 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
/* Notify the debugger we have added some objects. */
_dl_debug_addr->r_state = RT_ADD;
_dl_debug_state();
+
+ /* Run pre-initialization functions for the executable. */
+ _dl_run_array_forward(_dl_loaded_modules->dynamic_info[DT_PREINIT_ARRAY],
+ _dl_loaded_modules->dynamic_info[DT_PREINIT_ARRAYSZ],
+ _dl_loaded_modules->loadaddr);
+
+ /* Run initialization functions for loaded objects. For the
+ main executable, they will be run from __uClibc_main. */
for (i = nlist; i; --i) {
tpnt = init_fini_list[i-1];
tpnt->init_fini = NULL; /* Clear, since alloca was used */
@@ -919,20 +928,23 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
}
/* Find the real malloc function and make ldso functions use that from now on */
- _dl_malloc_function = (void* (*)(size_t)) (intptr_t) _dl_find_hash("malloc",
- _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
+ _dl_malloc_function = (void* (*)(size_t)) (intptr_t)
+ _dl_find_hash("malloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
#if USE_TLS
/* Find the real functions and make ldso functions use them from now on */
_dl_calloc_function = (void* (*)(size_t, size_t)) (intptr_t)
- _dl_find_hash("calloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
+ _dl_find_hash("calloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
_dl_realloc_function = (void* (*)(void *, size_t)) (intptr_t)
- _dl_find_hash("recalloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
+ _dl_find_hash("realloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
_dl_free_function = (void (*)(void *)) (intptr_t)
- _dl_find_hash("free", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
+ _dl_find_hash("free", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
_dl_memalign_function = (void* (*)(size_t, size_t)) (intptr_t)
- _dl_find_hash("memalign", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
-
+ _dl_find_hash("memalign", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
if (!was_tls_init_tp_called && _dl_tls_max_dtv_idx > 0)
++_dl_tls_generation;
@@ -947,7 +959,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
TLS we know the thread pointer was initialized earlier. */
if (! tls_init_tp_called)
{
- const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
+ const char *lossage = (char *) TLS_INIT_TP (tcbp, USE___THREAD);
if (__builtin_expect (lossage != NULL, 0))
{
_dl_debug_early("cannot set up thread-local storage: %s\n", lossage);
diff --git a/ldso/ldso/sh/dl-debug.h b/ldso/ldso/sh/dl-debug.h
index e862da1ee..e2e74f8e4 100644
--- a/ldso/ldso/sh/dl-debug.h
+++ b/ldso/ldso/sh/dl-debug.h
@@ -36,6 +36,8 @@ static const char *_dl_reltypes_tab[] =
[25] "R_SH_SWITCH16","R_SH_SWITCH32","R_SH_USES",
[28] "R_SH_COUNT", "R_SH_ALIGN", "R_SH_CODE", "R_SH_DATA",
[32] "R_SH_LABEL", "R_SH_SWITCH8", "R_SH_GNU_VTINHERIT","R_SH_GNU_VTENTRY",
+[144] "R_SH_TLS_GD_32","R_SH_TLS_LD_32", "R_SH_TLS_LDO_32", "R_SH_TLS_IE_32",
+[148] "R_SH_TLS_LE_32","R_SH_TLS_DTPMOD32", "R_SH_TLS_DTPOFF32", "R_SH_TLS_TPOFF32",
[160] "R_SH_GOT32", "R_SH_PLT32", "R_SH_COPY", "R_SH_GLOB_DAT",
[164] "R_SH_JMP_SLOT","R_SH_RELATIVE","R_SH_GOTOFF", "R_SH_GOTPC",
};
diff --git a/ldso/ldso/sh/dl-startup.h b/ldso/ldso/sh/dl-startup.h
index 63a65940c..bd51cebe0 100644
--- a/ldso/ldso/sh/dl-startup.h
+++ b/ldso/ldso/sh/dl-startup.h
@@ -3,6 +3,7 @@
* needed for this architecture. */
asm(
+ " .text\n"
" .globl _start\n"
" .type _start,@function\n"
"_start:\n"
diff --git a/ldso/ldso/sh/dl-sysdep.h b/ldso/ldso/sh/dl-sysdep.h
index da109782e..abe0a123f 100644
--- a/ldso/ldso/sh/dl-sysdep.h
+++ b/ldso/ldso/sh/dl-sysdep.h
@@ -6,6 +6,7 @@
/* Define this if the system uses RELOCA. */
#define ELF_USES_RELOCA
#include <elf.h>
+#include <tls.h>
/*
* Initialization sequence for a GOT.
*/
@@ -93,9 +94,17 @@ _dl_urem(unsigned int n, unsigned int base)
define the value.
ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
of the main executable's symbols, as for a COPY reloc. */
+#if defined USE_TLS
+# define elf_machine_type_class(type) \
+ ((((type) == R_SH_JMP_SLOT || (type) == R_SH_TLS_DTPMOD32 \
+ || (type) == R_SH_TLS_DTPOFF32 || (type) == R_SH_TLS_TPOFF32) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
+#else
#define elf_machine_type_class(type) \
((((type) == R_SH_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
| (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
+#endif
/* Return the link-time address of _DYNAMIC. Conveniently, this is the
first element of the GOT. This must be inlined in a function which
diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c
index c34acdf95..db86b0c0c 100644
--- a/ldso/ldso/sh/elfinterp.c
+++ b/ldso/ldso/sh/elfinterp.c
@@ -77,7 +77,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
got_addr = (char **) instr_addr;
/* Get the address of the GOT entry */
- new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
+ new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
+
if (unlikely(!new_addr)) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
_dl_exit(1);
@@ -166,6 +167,10 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
#if defined (__SUPPORT_LD_DEBUG__)
unsigned long old_val;
#endif
+#if USE_TLS
+struct elf_resolve *tls_tpnt = NULL;
+#endif
+
reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
@@ -175,23 +180,33 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
if (symtab_index) {
symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
- elf_machine_type_class(reloc_type));
-
+ elf_machine_type_class(reloc_type), &tls_tpnt);
/*
* We want to allow undefined references to weak symbols - this might
* have been intentional. We should not be linking local symbols
* here, so all bases should be covered.
*/
- if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
+
+ if (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) &&(ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
- _dl_exit (1);
+
+ /* Let the caller to handle the error: it may be non fatal if called from dlopen */
+ return 1;
}
}
#if defined (__SUPPORT_LD_DEBUG__)
old_val = *reloc_addr;
#endif
+
+#if USE_TLS
+ /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous' symbol.
+ This is the casa of a static tls variable, so the lookup module is just
+ that one is referencing the tls variable. */
+ if(!tls_tpnt)
+ tls_tpnt = tpnt;
+#endif
switch (reloc_type) {
case R_SH_NONE:
break;
@@ -218,12 +233,27 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
case R_SH_RELATIVE:
*reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend;
break;
+#if USE_TLS
+ case R_SH_TLS_DTPMOD32:
+ *reloc_addr = tls_tpnt->l_tls_modid;
+ break;
+
+ case R_SH_TLS_DTPOFF32:
+ *reloc_addr = symbol_addr;
+ break;
+
+ case R_SH_TLS_TPOFF32:
+ CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
+ *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend;
+ break;
+#endif
default:
- return -1; /*call _dl_exit(1) */
+
+ return -1;
}
#if defined (__SUPPORT_LD_DEBUG__)
if (_dl_debug_reloc && _dl_debug_detail)
- _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
+ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, *reloc_addr, reloc_addr);
#endif
return 0;
@@ -256,11 +286,11 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
*reloc_addr += (unsigned long) tpnt->loadaddr;
break;
default:
- return -1; /*call _dl_exit(1) */
+ return -1;
}
#if defined (__SUPPORT_LD_DEBUG__)
if (_dl_debug_reloc && _dl_debug_detail)
- _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
+ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, *reloc_addr, reloc_addr);
#endif
return 0;
diff --git a/ldso/libdl/Makefile.in b/ldso/libdl/Makefile.in
index 245832447..b6384a22c 100644
--- a/ldso/libdl/Makefile.in
+++ b/ldso/libdl/Makefile.in
@@ -12,10 +12,6 @@ CFLAGS-libdl += -I$(top_srcdir)ldso/ldso/$(TARGET_ARCH) -I$(top_srcdir)ldso/incl
CFLAGS-libdl += -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\"
-ifeq ($(SUPPORT_LD_DEBUG),y)
-CFLAGS-libdl += -D__SUPPORT_LD_DEBUG__
-endif
-
CFLAGS-libdl.c := -DLDSO_ELFINTERP=\"$(TARGET_ARCH)/elfinterp.c\"
LDFLAGS-libdl.so := $(LDFLAGS) -fini dl_cleanup
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index 462de4f3d..cd18729a9 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -32,59 +32,62 @@
#include <ldso.h>
#include <stdio.h>
+#include <tls.h>
#if USE_TLS
-# include <ldsodefs.h>
+#include <ldsodefs.h>
+extern void (*_dl_init_static_tls) (struct link_map *);
+extern void _dl_add_to_slotinfo(struct link_map *l);
#endif
-
#ifdef SHARED
-
-#if USE_TLS
+# if USE_TLS
# include <dl-tls.h>
-
-extern void _dl_add_to_slotinfo(struct link_map *l);
extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
-extern struct elf_resolve *_dl_tls_reloc_tpnt;
-extern ElfW(Sym) *_dl_tls_reloc_sym;
-#endif
+# endif
/* When libdl is loaded as a shared library, we need to load in
* and use a pile of symbols from ldso... */
-extern char *_dl_find_hash(const char *, struct dyn_elf *, struct elf_resolve *, int);
-extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **,
- struct elf_resolve *, char *, int);
+extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **, struct elf_resolve *, char *, int);
extern int _dl_fixup(struct dyn_elf *rpnt, int lazy);
extern void _dl_protect_relro(struct elf_resolve * tpnt);
extern int _dl_errno;
extern struct dyn_elf *_dl_symbol_tables;
extern struct dyn_elf *_dl_handles;
extern struct elf_resolve *_dl_loaded_modules;
+extern void _dl_free (void *__ptr);
extern struct r_debug *_dl_debug_addr;
extern unsigned long _dl_error_number;
extern void *(*_dl_malloc_function)(size_t);
extern void _dl_run_init_array(struct elf_resolve *);
extern void _dl_run_fini_array(struct elf_resolve *);
-#ifdef __LDSO_CACHE_SUPPORT__
+# ifdef __LDSO_CACHE_SUPPORT__
int _dl_map_cache(void);
int _dl_unmap_cache(void);
-#endif
-#ifdef __mips__
+# endif
+# ifdef __mips__
extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
-#endif
-#ifdef __SUPPORT_LD_DEBUG__
+# endif
+# ifdef __SUPPORT_LD_DEBUG__
extern char *_dl_debug;
-#endif
-
-
+# endif
#else /* SHARED */
/* When libdl is linked as a static library, we need to replace all
* the symbols that otherwise would have been loaded in from ldso... */
-#ifdef __SUPPORT_LD_DEBUG__
+# ifdef __SUPPORT_LD_DEBUG__
+/* Needed for 'strstr' prototype' */
+#include <string.h>
char *_dl_debug = 0;
-#endif
+char *_dl_debug_symbols = 0;
+char *_dl_debug_move = 0;
+char *_dl_debug_reloc = 0;
+char *_dl_debug_detail = 0;
+char *_dl_debug_nofixups = 0;
+char *_dl_debug_bindings = 0;
+int _dl_debug_file = 2;
+# endif
const char *_dl_progname = ""; /* Program name */
char *_dl_library_path = 0; /* Where we look for libraries */
char *_dl_ldsopath = 0; /* Location of the shared lib loader */
@@ -93,16 +96,17 @@ size_t _dl_pagesize = PAGE_SIZE; /* Store the page size for use later
/* This global variable is also to communicate with debuggers such as gdb. */
struct r_debug *_dl_debug_addr = NULL;
#define _dl_malloc malloc
+#define _dl_free free
#include "../ldso/dl-debug.c"
-#if USE_TLS
-#include "../ldso/dl-tls.c"
+
+# if USE_TLS
/*
* Giving this initialized value preallocates some surplus bytes in the
* static TLS area, see __libc_setup_tls (libc-tls.c).
*/
size_t _dl_tls_static_size = 2048;
-#endif
+# endif
#include LDSO_ELFINTERP
#include "../ldso/dl-hash.c"
#define _dl_trace_loaded_objects 0
@@ -167,18 +171,18 @@ static const char *dl_error_names[] = {
*/
static void *
internal_function
-_dl_tls_symaddr(struct link_map *map, const ElfW(Sym) *ref)
+_dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
{
# ifndef DONT_USE_TLS_INDEX
tls_index tmp =
{
.ti_module = map->l_tls_modid,
- .ti_offset = ref->st_value
+ .ti_offset = st_value
};
return __TLS_GET_ADDR (&tmp);
# else
- return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
+ return __TLS_GET_ADDR (map->l_tls_modid, st_value);
# endif
}
#endif
@@ -274,7 +278,7 @@ void *dlopen(const char *libname, int flag)
struct init_fini_list *tmp, *runp, *runp2, *dep_list;
unsigned int nlist, i;
struct elf_resolve **init_fini_list;
-#ifdef USE_TLS
+#if USE_TLS
bool any_tls = false;
#endif
@@ -290,6 +294,25 @@ void *dlopen(const char *libname, int flag)
if (!libname)
return _dl_symbol_tables;
+#ifndef SHARED
+# ifdef __SUPPORT_LD_DEBUG__
+ _dl_debug = getenv("LD_DEBUG");
+ if (_dl_debug) {
+ if (_dl_strstr(_dl_debug, "all")) {
+ _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
+ = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
+ } else {
+ _dl_debug_detail = strstr(_dl_debug, "detail");
+ _dl_debug_move = strstr(_dl_debug, "move");
+ _dl_debug_symbols = strstr(_dl_debug, "sym");
+ _dl_debug_reloc = strstr(_dl_debug, "reloc");
+ _dl_debug_nofixups = strstr(_dl_debug, "nofix");
+ _dl_debug_bindings = strstr(_dl_debug, "bind");
+ }
+ }
+# endif
+#endif
+
_dl_map_cache();
/*
@@ -317,6 +340,11 @@ void *dlopen(const char *libname, int flag)
if (getenv("LD_BIND_NOW"))
now_flag = RTLD_NOW;
+#ifndef SHARED
+ /* When statically linked, the _dl_library_path is not yet initialized */
+ _dl_library_path = getenv("LD_LIBRARY_PATH");
+#endif
+
/* Try to load the specified library */
_dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
(char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
@@ -377,36 +405,31 @@ void *dlopen(const char *libname, int flag)
tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
- if (tpnt1->usage_count == 1) {
- tpnt1->init_flag |= DL_OPENED;
- /* This list is for dlsym() and relocation */
- dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
- _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
- dyn_ptr = dyn_ptr->next;
- dyn_ptr->dyn = tpnt1;
- }
- if (tpnt1->init_flag & DL_OPENED) {
- /* Used to record RTLD_LOCAL scope */
- tmp = alloca(sizeof(struct init_fini_list));
- tmp->tpnt = tpnt1;
- tmp->next = runp->tpnt->init_fini;
- runp->tpnt->init_fini = tmp;
-
- for (tmp=dep_list; tmp; tmp = tmp->next) {
- if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
- _dl_if_debug_print("Circular dependency, skipping '%s',\n",
- tmp->tpnt->libname);
- tpnt1->usage_count--;
- break;
- }
- }
- if (!tmp) { /* Don't add if circular dependency detected */
- runp2->next = alloca(sizeof(*runp));
- runp2 = runp2->next;
- runp2->tpnt = tpnt1;
- runp2->next = NULL;
+ /* This list is for dlsym() and relocation */
+ dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+ _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
+ dyn_ptr = dyn_ptr->next;
+ dyn_ptr->dyn = tpnt1;
+ /* Used to record RTLD_LOCAL scope */
+ tmp = alloca(sizeof(struct init_fini_list));
+ tmp->tpnt = tpnt1;
+ tmp->next = runp->tpnt->init_fini;
+ runp->tpnt->init_fini = tmp;
+
+ for (tmp=dep_list; tmp; tmp = tmp->next) {
+ if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
+ _dl_if_debug_print("Circular dependency, skipping '%s',\n",
+ tmp->tpnt->libname);
+ tpnt1->usage_count--;
+ break;
}
}
+ if (!tmp) { /* Don't add if circular dependency detected */
+ runp2->next = alloca(sizeof(*runp));
+ runp2 = runp2->next;
+ runp2->tpnt = tpnt1;
+ runp2->next = NULL;
+ }
}
}
}
@@ -454,8 +477,8 @@ void *dlopen(const char *libname, int flag)
fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
runp = init_fini_list[i]->init_fini;
for (; runp; runp = runp->next)
- printf(" %s ", runp->tpnt->libname);
- printf("\n");
+ fprintf(stderr, " %s ", runp->tpnt->libname);
+ fprintf(stderr, "\n");
}
}
#endif
@@ -485,40 +508,42 @@ void *dlopen(const char *libname, int flag)
}
/* TODO: Should we set the protections of all pages back to R/O now ? */
+
#if USE_TLS
- tpnt = dyn_chain->dyn;
- /*
- * Only add TLS memory if this object is loaded now and
- * therefore is not yet initialized.
- */
- if (!(tpnt->init_flag & INIT_FUNCS_CALLED)
- /* Only if the module defines thread local data. */
- && __builtin_expect(tpnt->l_tls_blocksize > 0, 0))
- {
- /*
- * Now that we know the object is loaded successfully the
- * modules containing TLS data have been added to the slot
- * info table. We might have to increase its size.
- */
- if(tpnt->l_need_tls_init)
- {
- tpnt->l_need_tls_init = 0;
+ for (i=0; i < nlist; i++) {
+ struct elf_resolve *tmp_tpnt = init_fini_list[i];
+ /* Only add TLS memory if this object is loaded now and
+ therefore is not yet initialized. */
+
+ if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
+ /* Only if the module defines thread local data. */
+ && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
+
+ /* Now that we know the object is loaded successfully add
+ modules containing TLS data to the slot info table. We
+ might have to increase its size. */
+ _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
+
+ /* It is the case in which we couldn't perform TLS static
+ initialization at relocation time, and we delayed it until
+ the relocation has been completed. */
+
+ if (tmp_tpnt->l_need_tls_init) {
+ tmp_tpnt->l_need_tls_init = 0;
# ifdef SHARED
- /*
- * Update the slot information data for at least the
- * generation of the DSO we are allocating data for.
- */
- _dl_update_slotinfo (tpnt->l_tls_modid);
+ /* Update the slot information data for at least the
+ generation of the DSO we are allocating data for. */
+ _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
# endif
- _dl_init_static_tls((struct link_map *) tpnt);
-
- _dl_assert(tpnt->l_need_tls_init == 0);
+ _dl_init_static_tls((struct link_map*)tmp_tpnt);
+ _dl_assert (tmp_tpnt->l_need_tls_init == 0);
}
/* We have to bump the generation counter. */
any_tls = true;
+ }
}
/* Bump the generation number if necessary. */
@@ -581,6 +606,11 @@ void *dlsym(void *vhandle, const char *name)
struct dyn_elf *rpnt;
void *ret;
+#if defined USE_TLS
+struct elf_resolve *tls_tpnt = NULL;
+#endif
+
+
handle = (struct dyn_elf *) vhandle;
/* First of all verify that we have a real handle
@@ -616,26 +646,18 @@ void *dlsym(void *vhandle, const char *name)
}
}
}
+ tpnt = NULL;
+ if (handle == _dl_symbol_tables)
+ tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
+ ret = _dl_find_hash((char*)name, handle, NULL, 0, &tls_tpnt);
+#if defined USE_TLS && defined SHARED
+ if(tls_tpnt) {
-#if defined(USE_TLS) && defined(SHARED)
- ret = _dl_find_hash((char*)name, handle, NULL, 1);
-
- if (ret)
- {
- if(ELF_ST_TYPE(_dl_tls_reloc_sym->st_info) == STT_TLS)
- {
- /*
- * The found symbol is a thread-local storage variable.
- * Return the address for it to the current thread.
- */
- ret = _dl_tls_symaddr((struct link_map *) _dl_tls_reloc_tpnt,
- _dl_tls_reloc_sym);
- }
+ /* The found symbol is a thread-local storage variable.
+ Return the address for to the current thread. */
+ ret = _dl_tls_symaddr ((struct link_map *)tls_tpnt, (Elf32_Addr)ret);
}
- else
-#else
- ret = _dl_find_hash((char*)name, handle, NULL, 0);
#endif
/*
@@ -819,7 +841,22 @@ static int do_dlclose(void *vhandle, int need_fini)
# else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
- }
+ } else {
+
+#define TLS_DTV_UNALLOCATED ((void *) -1l)
+
+ dtv_t *dtv = THREAD_DTV ();
+
+ _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
+ if(dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
+ /* Note that free is called for NULL is well. We
+ deallocate even if it is this dtv entry we are
+ supposed to load. The reason is that we call
+ memalign and not malloc. */
+ _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
+ dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
+ }
+ }
}
#endif
@@ -867,7 +904,7 @@ static int do_dlclose(void *vhandle, int need_fini)
free(tpnt->libname);
free(tpnt);
}
- }
+ } /* end of for (j = 0; j < handle->init_fini.nlist; ++j) */
free(handle->init_fini.init_fini);
free(handle);
@@ -917,7 +954,7 @@ char *dlerror(void)
}
/*
- * Dump information to stderrr about the current loaded modules
+ * Dump information to stderr about the current loaded modules
*/
#ifdef __USE_GNU
static char *type[] = { "Lib", "Exe", "Int", "Mod" };