summaryrefslogtreecommitdiff
path: root/ldso/ldso/arm
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 /ldso/ldso/arm
parentd21497f9fba95688e464ae712bd6b4c0fbc4ea13 (diff)
ldso/: tls support for dynamic linker
Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
Diffstat (limited to 'ldso/ldso/arm')
-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
6 files changed, 206 insertions, 18 deletions
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__ */
+