summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Foxley <austinf@cetoncorp.com>2009-09-19 10:04:05 -0700
committerAustin Foxley <austinf@cetoncorp.com>2009-09-26 09:37:18 -0700
commit534661b91c98492995274c364c8177c45efc63db (patch)
tree333c655a3159fdb72a693a7335ba347094dfd57a
parentd21497f9fba95688e464ae712bd6b4c0fbc4ea13 (diff)
ldso/: tls support for dynamic linker
Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
-rw-r--r--ldso/include/dl-hash.h61
-rw-r--r--ldso/include/ldso.h6
-rw-r--r--ldso/include/ldsodefs.h147
-rw-r--r--ldso/ldso/Makefile.in11
-rw-r--r--ldso/ldso/arm/aeabi_read_tp.S64
-rw-r--r--ldso/ldso/arm/dl-debug.h4
-rw-r--r--ldso/ldso/arm/dl-sysdep.h21
-rw-r--r--ldso/ldso/arm/elfinterp.c52
-rw-r--r--ldso/ldso/arm/resolve.S4
-rw-r--r--ldso/ldso/arm/thumb_atomics.S79
-rw-r--r--ldso/ldso/dl-elf.c67
-rw-r--r--ldso/ldso/dl-hash.c87
-rw-r--r--ldso/ldso/dl-startup.c14
-rw-r--r--ldso/ldso/dl-tls.c1048
-rw-r--r--ldso/ldso/i386/dl-sysdep.h7
-rw-r--r--ldso/ldso/i386/elfinterp.c32
-rw-r--r--ldso/ldso/ldso.c158
-rw-r--r--ldso/ldso/mips/elfinterp.c71
-rw-r--r--ldso/ldso/sh/dl-debug.h2
-rw-r--r--ldso/ldso/sh/dl-sysdep.h9
-rw-r--r--ldso/ldso/sh/elfinterp.c39
-rw-r--r--ldso/ldso/sparc/dl-sysdep.h4
-rw-r--r--ldso/ldso/sparc/elfinterp.c75
-rw-r--r--ldso/libdl/libdl.c325
24 files changed, 2239 insertions, 148 deletions
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index e7ca4aba8..1b28a34b6 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -34,7 +34,32 @@ struct elf_resolve {
struct elf_resolve * next;
struct elf_resolve * prev;
/* Nothing after this address is used by gdb. */
- ElfW(Addr) mapaddr; /* Address at which ELF segments (either main app and DSO) are mapped into */
+
+#if USE_TLS
+ /* Thread-local storage related info. */
+
+ /* Start of the initialization image. */
+ void *l_tls_initimage;
+ /* Size of the initialization image. */
+ size_t l_tls_initimage_size;
+ /* Size of the TLS block. */
+ size_t l_tls_blocksize;
+ /* Alignment requirement of the TLS block. */
+ size_t l_tls_align;
+ /* Offset of first byte module alignment. */
+ size_t l_tls_firstbyte_offset;
+# ifndef NO_TLS_OFFSET
+# define NO_TLS_OFFSET 0
+# endif
+ /* For objects present at startup time: offset in the static TLS block. */
+ ptrdiff_t l_tls_offset;
+ /* Index of the module in the dtv array. */
+ size_t l_tls_modid;
+ /* Nonzero if _dl_init_static_tls should be called for this module */
+ unsigned int l_need_tls_init:1;
+#endif
+
+ ElfW(Addr) mapaddr;
enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
struct dyn_elf * symbol_scope;
unsigned short usage_count;
@@ -106,26 +131,31 @@ struct elf_resolve {
extern struct dyn_elf * _dl_symbol_tables;
extern struct elf_resolve * _dl_loaded_modules;
-extern struct dyn_elf * _dl_handles;
+extern struct dyn_elf * _dl_handles;
extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
DL_LOADADDR_TYPE loadaddr, unsigned long * dynamic_info,
unsigned long dynamic_addr, unsigned long dynamic_size);
-extern char * _dl_lookup_hash(const char * name, struct dyn_elf * rpnt,
- struct elf_resolve *mytpnt, int type_class
-#ifdef __FDPIC__
- , struct elf_resolve **tpntp
+#if USE_TLS || defined __FDPIC__
+#define _DL_LOOKUP_HASH_NEEDS_EXTRA_TPNT
+#define _DL_LOOKUP_HASH_EXTRA_TPNT ,struct elf_resolve **tpntp
+#else
+#undef _DL_LOOKUP_HASH_NEEDS_EXTRA_TPNT
+#define _DL_LOOKUP_HASH_EXTRA_TPNT
#endif
- );
+extern char * _dl_lookup_hash(const char * name, struct dyn_elf * rpnt,
+ struct elf_resolve *mytpnt, int type_class _DL_LOOKUP_HASH_EXTRA_TPNT);
+
static __always_inline char *_dl_find_hash(const char *name, struct dyn_elf *rpnt,
- struct elf_resolve *mytpnt, int type_class)
+ struct elf_resolve *mytpnt, int type_class,
+ struct elf_resolve **tpntp)
{
-#ifdef __FDPIC__
- return _dl_lookup_hash(name, rpnt, mytpnt, type_class, NULL);
+#ifdef _DL_LOOKUP_HASH_NEEDS_EXTRA_TPNT
+ return _dl_lookup_hash(name, rpnt, mytpnt, type_class, tpntp);
#else
- return _dl_lookup_hash(name, rpnt, mytpnt, type_class);
+ return _dl_lookup_hash(name, rpnt, mytpnt, type_class);
#endif
}
@@ -148,8 +178,11 @@ static __inline__ int _dl_symbol(char * name)
#define LD_ERROR_NOTDYN 5
#define LD_ERROR_MMAP_FAILED 6
#define LD_ERROR_NODYNAMIC 7
-#define LD_WRONG_RELOCS 8
-#define LD_BAD_HANDLE 9
-#define LD_NO_SYMBOL 10
+#define LD_ERROR_TLS_FAILED 8
+#define LD_WRONG_RELOCS 9
+#define LD_BAD_HANDLE 10
+#define LD_NO_SYMBOL 11
+
+
#endif /* _LD_HASH_H_ */
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index dc4d92db6..1dd35febc 100644
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -38,6 +38,10 @@
#include <dl-string.h>
/* Now the ldso specific headers */
#include <dl-elf.h>
+#ifdef __UCLIBC_HAS_TLS__
+/* Defines USE_TLS */
+#include <tls.h>
+#endif
#include <dl-hash.h>
/* common align masks, if not specified by sysdep headers */
@@ -113,6 +117,8 @@ extern int _dl_debug_file;
#endif
extern void *_dl_malloc(size_t size);
+extern void * _dl_calloc(size_t __nmemb, size_t __size);
+extern void * _dl_realloc(void * __ptr, size_t __size);
extern void _dl_free(void *);
extern char *_dl_getenv(const char *symbol, char **envp);
extern void _dl_unsetenv(const char *symbol, char **envp);
diff --git a/ldso/include/ldsodefs.h b/ldso/include/ldsodefs.h
new file mode 100644
index 000000000..432c7b848
--- /dev/null
+++ b/ldso/include/ldsodefs.h
@@ -0,0 +1,147 @@
+#ifndef _LDSODEFS_H
+#define _LDSODEFS_H 1
+
+#include <bits/kernel-features.h>
+
+#include <features.h>
+#include <tls.h>
+
+#ifdef __mips__
+/* The MIPS ABI specifies that the dynamic section has to be read-only. */
+
+#define DL_RO_DYN_SECTION 1
+
+/* TODO: Import in 64-bit relocations from glibc. */
+#endif
+
+#ifndef SHARED
+# define EXTERN extern
+#else
+# ifdef IS_IN_rtld
+# define EXTERN
+# else
+# define EXTERN extern
+# endif
+#endif
+
+/* Non-shared code has no support for multiple namespaces. */
+#ifdef SHARED
+# define DL_NNS 16
+#else
+# define DL_NNS 1
+#endif
+
+#define GL(x) _##x
+#define GLRO(x) _##x
+
+/* Variable pointing to the end of the stack (or close to it). This value
+ must be constant over the runtime of the application. Some programs
+ might use the variable which results in copy relocations on some
+ platforms. But this does not matter, ld.so can always use the local
+ copy. */
+extern void *__libc_stack_end;
+
+/* Determine next available module ID. */
+extern size_t _dl_next_tls_modid (void) internal_function attribute_hidden;
+
+/* Calculate offset of the TLS blocks in the static TLS block. */
+extern void _dl_determine_tlsoffset (void) internal_function attribute_hidden;
+
+/* Set up the data structures for TLS, when they were not set up at startup.
+ Returns nonzero on malloc failure.
+ This is called from _dl_map_object_from_fd or by libpthread. */
+extern int _dl_tls_setup (void) internal_function;
+rtld_hidden_proto (_dl_tls_setup)
+
+/* Allocate memory for static TLS block (unless MEM is nonzero) and dtv. */
+extern void *_dl_allocate_tls (void *mem) internal_function;
+
+/* Get size and alignment requirements of the static TLS block. */
+extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
+ internal_function;
+
+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)
+ internal_function attribute_hidden;
+extern void *_dl_allocate_tls_init (void *) internal_function;
+
+/* Deallocate memory allocated with _dl_allocate_tls. */
+extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
+
+extern void _dl_nothread_init_static_tls (struct link_map *) internal_function attribute_hidden;
+
+/* Highest dtv index currently needed. */
+EXTERN size_t _dl_tls_max_dtv_idx;
+/* Flag signalling whether there are gaps in the module ID allocation. */
+EXTERN bool _dl_tls_dtv_gaps;
+/* Information about the dtv slots. */
+EXTERN struct dtv_slotinfo_list
+{
+ size_t len;
+ struct dtv_slotinfo_list *next;
+ struct dtv_slotinfo
+ {
+ size_t gen;
+ bool is_static;
+ struct link_map *map;
+ } slotinfo[0];
+} *_dl_tls_dtv_slotinfo_list;
+/* Number of modules in the static TLS block. */
+EXTERN size_t _dl_tls_static_nelem;
+/* Size of the static TLS block. */
+EXTERN size_t _dl_tls_static_size;
+/* Size actually allocated in the static TLS block. */
+EXTERN size_t _dl_tls_static_used;
+/* Alignment requirement of the static TLS block. */
+EXTERN size_t _dl_tls_static_align;
+/* Function pointer for catching TLS errors. */
+EXTERN void **(*_dl_error_catch_tsd) (void) __attribute__ ((const));
+
+/* Number of additional entries in the slotinfo array of each slotinfo
+ list element. A large number makes it almost certain take we never
+ have to iterate beyond the first element in the slotinfo list. */
+# define TLS_SLOTINFO_SURPLUS (62)
+
+/* Number of additional slots in the dtv allocated. */
+# define DTV_SURPLUS (14)
+
+ /* Initial dtv of the main thread, not allocated with normal malloc. */
+ EXTERN void *_dl_initial_dtv;
+ /* Generation counter for the dtv. */
+ EXTERN size_t _dl_tls_generation;
+
+ EXTERN void (*_dl_init_static_tls) (struct link_map *);
+
+/* We have the auxiliary vector. */
+#define HAVE_AUX_VECTOR
+
+/* We can assume that the kernel always provides the AT_UID, AT_EUID,
+ AT_GID, and AT_EGID values in the auxiliary vector from 2.4.0 or so on. */
+#if __ASSUME_AT_XID
+# define HAVE_AUX_XID
+#endif
+
+/* We can assume that the kernel always provides the AT_SECURE value
+ in the auxiliary vector from 2.5.74 or so on. */
+#if __ASSUME_AT_SECURE
+# define HAVE_AUX_SECURE
+#endif
+
+/* Starting with one of the 2.4.0 pre-releases the Linux kernel passes
+ up the page size information. */
+#if __ASSUME_AT_PAGESIZE
+# define HAVE_AUX_PAGESIZE
+#endif
+
+#endif
diff --git a/ldso/ldso/Makefile.in b/ldso/ldso/Makefile.in
index a74c36e5e..350cc8108 100644
--- a/ldso/ldso/Makefile.in
+++ b/ldso/ldso/Makefile.in
@@ -15,6 +15,17 @@ 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....
+# On arm, gcc-4.3.x onwards -Os emits calls to libgcc, which calls _div0,
+# which tries to call raise(). And raise comes from libc so a catch 22.
+# Using -O2 instead. We could have use -fno-early-inlining with -Os too.
+
+CFLAGS-ldso += -O2 -g
+endif
+
CFLAGS-ldso/ldso/$(TARGET_ARCH)/ := $(CFLAGS-ldso)
CFLAGS-ldso.c := -DLDSO_ELFINTERP=\"$(TARGET_ARCH)/elfinterp.c\" $(CFLAGS-ldso)
diff --git a/ldso/ldso/arm/aeabi_read_tp.S b/ldso/ldso/arm/aeabi_read_tp.S
new file mode 100644
index 000000000..f81bae676
--- /dev/null
+++ b/ldso/ldso/arm/aeabi_read_tp.S
@@ -0,0 +1,64 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <features.h>
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+
+#include <sysdep.h>
+#include <tls.h>
+
+/* GCC will emit calls to this routine under -mtp=soft. Linux has an
+ equivalent helper function (which clobbers fewer registers than
+ a normal function call) in a high page of memory; tail call to the
+ helper.
+
+ This function is exported from libc for use by user code. libpthread, librt,
+ and the dynamic linker get their own private copies, for
+ performance (and in the case of ld.so, out of necessity); those are
+ all hidden. */
+
+#ifndef NOT_IN_libc
+ .global __aeabi_read_tp
+#else
+ .hidden __aeabi_read_tp
+#endif
+ENTRY (__aeabi_read_tp)
+ mov r0, #0xffff0fff
+ sub pc, r0, #31
+END (__aeabi_read_tp)
+
+#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */
+
diff --git a/ldso/ldso/arm/dl-debug.h b/ldso/ldso/arm/dl-debug.h
index d5103202c..1bca6ff36 100644
--- a/ldso/ldso/arm/dl-debug.h
+++ b/ldso/ldso/arm/dl-debug.h
@@ -33,12 +33,14 @@ static const char *_dl_reltypes_tab[] =
[4] "R_ARM_PC13", "R_ARM_ABS16", "R_ARM_ABS12", "R_ARM_THM_ABS5",
[8] "R_ARM_ABS8", "R_ARM_SBREL32","R_ARM_THM_PC22", "R_ARM_THM_PC8",
[12] "R_ARM_AMP_VCALL9", "R_ARM_SWI24", "R_ARM_THM_SWI8", "R_ARM_XPC25",
- [16] "R_ARM_THM_XPC22",
+ [16] "R_ARM_THM_XPC22", "R_ARM_TLS_DTPMOD32", "R_ARM_TLS_DTPOFF32", "R_ARM_TLS_TPOFF32",
[20] "R_ARM_COPY", "R_ARM_GLOB_DAT","R_ARM_JUMP_SLOT", "R_ARM_RELATIVE",
[24] "R_ARM_GOTOFF", "R_ARM_GOTPC", "R_ARM_GOT32", "R_ARM_PLT32",
[32] "R_ARM_ALU_PCREL_7_0","R_ARM_ALU_PCREL_15_8","R_ARM_ALU_PCREL_23_15","R_ARM_LDR_SBREL_11_0",
[36] "R_ARM_ALU_SBREL_19_12","R_ARM_ALU_SBREL_27_20",
[100] "R_ARM_GNU_VTENTRY","R_ARM_GNU_VTINHERIT","R_ARM_THM_PC11","R_ARM_THM_PC9",
+ [104] "R_ARM_TLS_GD32","R_ARM_TLS_LDM32","R_ARM_TLS_LDO32","R_ARM_TLS_IE32",
+ [108] "R_ARM_TLS_LE32","R_ARM_TLS_LDO12","R_ARM_TLS_LE12","R_ARM_TLS_IE12GP",
[249] "R_ARM_RXPC25", "R_ARM_RSBREL32", "R_ARM_THM_RPC22", "R_ARM_RREL32",
[253] "R_ARM_RABS22", "R_ARM_RPC24", "R_ARM_RBASE",
};
diff --git a/ldso/ldso/arm/dl-sysdep.h b/ldso/ldso/arm/dl-sysdep.h
index 75c58b0ec..5a2912ab5 100644
--- a/ldso/ldso/arm/dl-sysdep.h
+++ b/ldso/ldso/arm/dl-sysdep.h
@@ -5,6 +5,9 @@
* Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
*/
+#ifndef _ARCH_DL_SYSDEP
+#define _ARCH_DL_SYSDEP
+
/* Define this if the system uses RELOCA. */
#undef ELF_USES_RELOCA
#include <elf.h>
@@ -55,12 +58,21 @@ static __always_inline unsigned long arm_modulus(unsigned long m, unsigned long
struct elf_resolve;
unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
- PLT entries should not be allowed to define the value.
+/* 4096 bytes alignment */
+#define PAGE_ALIGN 0xfffff000
+#define ADDR_ALIGN 0xfff
+#define OFFS_ALIGN 0x7ffff000
+
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+ TLS variable, so undefined references should not be allowed to
+ 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. */
-#define elf_machine_type_class(type) \
- ((((type) == R_ARM_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+#define elf_machine_type_class(type) \
+ ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32 \
+ || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32) \
+ * ELF_RTYPE_CLASS_PLT) \
| (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY))
/* Return the link-time address of _DYNAMIC. Conveniently, this is the
@@ -136,6 +148,7 @@ elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
*reloc_addr += load_off;
} while (--relative_count);
}
+#endif /* !_ARCH_DL_SYSDEP */
#ifdef __ARM_EABI__
#define DL_MALLOC_ALIGN 8 /* EABI needs 8 byte alignment for STRD LDRD */
diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c
index 197975e4a..1469df016 100644
--- a/ldso/ldso/arm/elfinterp.c
+++ b/ldso/ldso/arm/elfinterp.c
@@ -50,7 +50,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
Elf32_Sym *symtab;
ELF_RELOC *rel_addr;
int symtab_index;
- char *new_addr;
+ unsigned long new_addr;
char **got_addr;
unsigned long instr_addr;
@@ -70,7 +70,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
/* Get the address of the GOT entry */
new_addr = _dl_find_hash(symname, tpnt->symbol_scope,
- tpnt, ELF_RTYPE_CLASS_PLT);
+ tpnt, ELF_RTYPE_CLASS_PLT, NULL);
if (unlikely(!new_addr)) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, symname);
@@ -89,13 +89,13 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
}
}
if (!_dl_debug_nofixups) {
- *got_addr = new_addr;
+ *got_addr = (char*)new_addr;
}
#else
- *got_addr = new_addr;
+ *got_addr = (char*)new_addr;
#endif
- return (unsigned long) new_addr;
+ return new_addr;
}
static int
@@ -188,28 +188,40 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
int symtab_index;
unsigned long *reloc_addr;
unsigned long symbol_addr;
+ const Elf32_Sym *def = 0;
+ struct elf_resolve *def_mod = 0;
int goof = 0;
- reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
+ reloc_addr = (unsigned long *) (tpnt->loadaddr
+ + (unsigned long) rpnt->r_offset);
+
reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
symbol_addr = 0;
if (symtab_index) {
-
- symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
- scope, tpnt, elf_machine_type_class(reloc_type));
+ symbol_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
+ scope, tpnt,
+ elf_machine_type_class(reloc_type),
+ &def_mod);
/*
* 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) {
- _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
- _dl_progname, strtab + symtab[symtab_index].st_name);
- _dl_exit (1);
+ if (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)
+ && (ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
+ /* This may be non-fatal if called from dlopen. */
+ return 1;
+
}
+ } else {
+ /* Relocs against STN_UNDEF are usually treated as using a
+ symbol value of zero, and using the module containing the
+ reloc itself. */
+ symbol_addr = symtab[symtab_index].st_value;
+ def_mod = tpnt;
}
#if defined (__SUPPORT_LD_DEBUG__)
@@ -265,6 +277,20 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
_dl_memcpy((void *) reloc_addr,
(void *) symbol_addr, symtab[symtab_index].st_size);
break;
+#if USE_TLS
+ case R_ARM_TLS_DTPMOD32:
+ *reloc_addr = def_mod->l_tls_modid;
+ break;
+
+ case R_ARM_TLS_DTPOFF32:
+ *reloc_addr += symbol_addr;
+ break;
+
+ case R_ARM_TLS_TPOFF32:
+ CHECK_STATIC_TLS ((struct link_map *) def_mod);
+ *reloc_addr += (symbol_addr + def_mod->l_tls_offset);
+ break;
+#endif
default:
return -1; /*call _dl_exit(1) */
}
diff --git a/ldso/ldso/arm/resolve.S b/ldso/ldso/arm/resolve.S
index b422c334d..08889d06e 100644
--- a/ldso/ldso/arm/resolve.S
+++ b/ldso/ldso/arm/resolve.S
@@ -95,6 +95,10 @@
#include <features.h>
+#define sl r10
+#define fp r11
+#define ip r12
+
.text
.align 4 @ 16 byte boundary and there are 32 bytes below (arm case)
#if !defined(__thumb__) || defined(__thumb2__)
diff --git a/ldso/ldso/arm/thumb_atomics.S b/ldso/ldso/arm/thumb_atomics.S
new file mode 100644
index 000000000..f6ae3db3c
--- /dev/null
+++ b/ldso/ldso/arm/thumb_atomics.S
@@ -0,0 +1,79 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <features.h>
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+
+#include <sysdep.h>
+
+#if defined __thumb__
+
+/* Out-of-line atomic operations that we can't do in Thumb mode.
+ This ends up in various libraries where it is needed (and
+ a few .a archives where it isn't). */
+
+ .hidden __thumb_swpb
+ENTRY (__thumb_swpb)
+ swpb r0, r0, [r1]
+ bx lr
+END (__thumb_swpb)
+
+ .hidden __thumb_swp
+ENTRY (__thumb_swp)
+ swp r0, r0, [r1]
+ bx lr
+END (__thumb_swp)
+
+ .hidden __thumb_cmpxchg
+ENTRY (__thumb_cmpxchg)
+ stmdb sp!, {r4, lr}
+ mov r4, r0
+0: ldr r3, [r2]
+ cmp r3, r4
+ bne 1f
+ mov r0, r4
+ mov r3, #0xffff0fff
+ mov lr, pc
+ add pc, r3, #(0xffff0fc0 - 0xffff0fff)
+ bcc 0b
+ mov r3, r4
+1: mov r0, r3
+ ldmia sp!, {r4, pc}
+END (__thumb_cmpxchg)
+
+#endif /* __thumb__ */
+#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */
+
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 89708497d..75e8f7186 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -329,6 +329,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;
@@ -433,6 +436,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++;
}
@@ -708,6 +734,37 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
tpnt->ppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(tpnt->loadaddr, epnt->e_phoff);
tpnt->n_phent = epnt->e_phnum;
+#if USE_TLS
+ 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 = 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 = 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 *) 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;
+ }
+ }
+#endif
+
/*
* Add this object into the symbol chain
*/
@@ -816,6 +873,16 @@ 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 4809c4348..3103d9f0b 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -157,18 +157,29 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
static __attribute_noinline__ const ElfW(Sym) *
check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int type_class)
{
- if (type_class & (sym->st_shndx == SHN_UNDEF))
- /* undefined symbol itself */
- return NULL;
-#ifdef __mips__
- if (sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT))
- return NULL;
-#endif
-
- if (sym->st_value == 0)
- /* No value */
- return NULL;
+#if USE_TLS
+ 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
&& ELF_ST_TYPE(sym->st_info) != STT_COMMON)
@@ -177,7 +188,7 @@ check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int typ
* code/data definitions
*/
return NULL;
-
+#endif
if (_dl_strcmp(strtab + sym->st_name, undef_name) != 0)
return NULL;
@@ -257,12 +268,11 @@ _dl_lookup_sysv_hash(struct elf_resolve *tpnt, ElfW(Sym) *symtab, unsigned long
* 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_lookup_hash(const char *name, struct dyn_elf *rpnt,
- struct elf_resolve *mytpnt, int type_class
-#ifdef __FDPIC__
- , struct elf_resolve **tpntp
-#endif
- )
+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 = NULL;
ElfW(Sym) *symtab;
@@ -270,8 +280,7 @@ char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt,
unsigned long elf_hash_number = 0xffffffff;
const ElfW(Sym) *sym = NULL;
- const ElfW(Sym) *weak_sym = 0;
- struct elf_resolve *weak_tpnt = 0;
+ char *weak_result = NULL;
#ifdef __LDSO_GNU_HASH_SUPPORT__
unsigned long gnu_hash_number = _dl_gnu_hash((const unsigned char *)name);
@@ -329,37 +338,29 @@ char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt,
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;