aboutsummaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile9
-rw-r--r--elf/dl-load.c4
-rw-r--r--elf/dl-reloc.c37
-rw-r--r--elf/rtld.c11
-rw-r--r--elf/tst-tls14.c56
-rw-r--r--elf/tst-tlsmod14a.c36
-rw-r--r--elf/tst-tlsmod14b.c2
7 files changed, 144 insertions, 11 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 7c654f86ae..bfecc360e2 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -148,7 +148,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
neededtest3 neededtest4 unload2 lateglobal initfirst global \
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
- tst-tls10 tst-tls11 tst-tls12 tst-tls13
+ tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14
# reldep9
test-srcs = tst-pathopt
tests-vis-yes = vismain
@@ -171,7 +171,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-tlsmod1 tst-tlsmod2 tst-tlsmod3 tst-tlsmod4 \
tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \
tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \
- tst-tlsmod13 tst-tlsmod13a \
+ tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \
circlemod1 circlemod1a circlemod2 circlemod2a \
circlemod3 circlemod3a \
reldep8mod1 reldep8mod2 reldep8mod3 \
@@ -428,6 +428,8 @@ tst-tlsmod8.so-no-z-defs = yes
tst-tlsmod9.so-no-z-defs = yes
tst-tlsmod10.so-no-z-defs = yes
tst-tlsmod12.so-no-z-defs = yes
+tst-tlsmod14a.so-no-z-defs = yes
+tst-tlsmod14b.so-no-z-defs = yes
circlemod2.so-no-z-defs = yes
circlemod3.so-no-z-defs = yes
circlemod3a.so-no-z-defs = yes
@@ -633,6 +635,9 @@ $(objpfx)tst-tls12: $(objpfx)tst-tlsmod12.so
$(objpfx)tst-tls13: $(libdl)
$(objpfx)tst-tls13.out: $(objpfx)tst-tlsmod13a.so
+$(objpfx)tst-tls14: $(objpfx)tst-tlsmod14a.so $(libdl)
+$(objpfx)tst-tls14.out:$(objpfx)tst-tlsmod14b.so
+
ifdef libdl
$(objpfx)tst-tls9-static: $(common-objpfx)dlfcn/libdl.a
$(objpfx)tst-tls9-static.out: $(objpfx)tst-tlsmod5.so $(objpfx)tst-tlsmod6.so
diff --git a/elf/dl-load.c b/elf/dl-load.c
index f3c9e82423..249ef84639 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -987,6 +987,10 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
l->l_tls_blocksize = ph->p_memsz;
l->l_tls_align = ph->p_align;
+ if (ph->p_align == 0)
+ l->l_tls_firstbyte_offset = 0;
+ else
+ l->l_tls_firstbyte_offset = ph->p_vaddr & (ph->p_align - 1);
l->l_tls_initimage_size = ph->p_filesz;
/* Since we don't know the load address yet only store the
offset. We will adjust it later. */
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 6165fe4aca..d82ea108d0 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -41,27 +41,39 @@
the static TLS area already allocated for each running thread. If this
object's TLS segment is too big to fit, we fail. If it fits,
we set MAP->l_tls_offset and return. */
-void
+int
internal_function __attribute_noinline__
_dl_allocate_static_tls (struct link_map *map)
{
size_t offset;
size_t used;
size_t check;
+ size_t freebytes;
+ size_t n;
+ size_t blsize;
+
+ /* If the alignment requirements are too high fail. */
+ if (map->l_tls_align > GL(dl_tls_static_align))
+ return 1;
# if TLS_TCB_AT_TP
- offset = roundup (GL(dl_tls_static_used) + map->l_tls_blocksize,
- map->l_tls_align);
- used = offset;
- check = offset + TLS_TCB_SIZE;
+ freebytes = GL(dl_tls_static_size) - GL(dl_tls_static_used) - TLS_TCB_SIZE;
+
+ blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
+ if (freebytes < blsize)
+ return 1;
+
+ n = (freebytes - blsize) / map->l_tls_align;
+
+ offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
+ - map->l_tls_firstbyte_offset);
+
+ map->l_tls_offset = GL(dl_tls_static_used) = offset;
# elif TLS_DTV_AT_TP
offset = roundup (GL(dl_tls_static_used), map->l_tls_align);
used = offset + map->l_tls_blocksize;
check = used;
/* dl_tls_static_used includes the TCB at the beginning. */
-# else
-# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
-# endif
if (check > GL(dl_tls_static_size))
{
@@ -72,6 +84,11 @@ shared object cannot be dlopen()ed: static TLS memory too small");
map->l_tls_offset = offset;
GL(dl_tls_static_used) = used;
+# else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+ return 0;
}
#endif
@@ -212,7 +229,9 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
#define CHECK_STATIC_TLS(map, sym_map) \
do { \
if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \
- _dl_allocate_static_tls (sym_map); \
+ if (_dl_allocate_static_tls (sym_map) != 0) \
+ INTUSE(_dl_signal_error) (0, sym_map->l_name, NULL, N_("\
+cannot allocate memory in static TLS block")); \
} while (0)
#include "dynamic-link.h"
diff --git a/elf/rtld.c b/elf/rtld.c
index 4a086c2d32..c63405ac99 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -227,6 +227,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
assert (info->l.l_tls_modid != 0);
GL(dl_rtld_map).l_tls_blocksize = info->l.l_tls_blocksize;
GL(dl_rtld_map).l_tls_align = info->l.l_tls_align;
+ GL(dl_rtld_map).l_tls_firstbyte_offset = info->l.l_tls_firstbyte_offset;
GL(dl_rtld_map).l_tls_initimage_size = info->l.l_tls_initimage_size;
GL(dl_rtld_map).l_tls_initimage = info->l.l_tls_initimage;
GL(dl_rtld_map).l_tls_offset = info->l.l_tls_offset;
@@ -347,6 +348,11 @@ _dl_start (void *arg)
bootstrap_map.l_tls_blocksize = phdr[cnt].p_memsz;
bootstrap_map.l_tls_align = phdr[cnt].p_align;
+ if (phdr[cnt].p_align == 0)
+ bootstrap_map.l_tls_firstbyte_offset = 0;
+ else
+ bootstrap_map.l_tls_firstbyte_offset = (phdr[cnt].p_vaddr
+ & (phdr[cnt].p_align - 1));
assert (bootstrap_map.l_tls_blocksize != 0);
bootstrap_map.l_tls_initimage_size = phdr[cnt].p_filesz;
bootstrap_map.l_tls_initimage = (void *) (bootstrap_map.l_addr
@@ -860,6 +866,11 @@ of this helper program; chances are you did not intend to run this program.\n\
check for this special but unimportant case. */
GL(dl_loaded)->l_tls_blocksize = ph->p_memsz;
GL(dl_loaded)->l_tls_align = ph->p_align;
+ if (ph->p_align == 0)
+ GL(dl_loaded)->l_tls_firstbyte_offset = 0;
+ else
+ GL(dl_loaded)->l_tls_firstbyte_offset = (ph->p_vaddr
+ & (ph->p_align - 1));
GL(dl_loaded)->l_tls_initimage_size = ph->p_filesz;
GL(dl_loaded)->l_tls_initimage = (void *) ph->p_vaddr;
diff --git a/elf/tst-tls14.c b/elf/tst-tls14.c
new file mode 100644
index 0000000000..4ae367a38f
--- /dev/null
+++ b/elf/tst-tls14.c
@@ -0,0 +1,56 @@
+/* Check alignment of TLS variable. */
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define AL 4096
+struct foo
+{
+ int i;
+} __attribute ((aligned (AL)));
+
+static __thread struct foo f;
+static struct foo g;
+
+
+extern int in_dso1 (void);
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ int fail = (((uintptr_t) &f) & (AL - 1)) != 0;
+ printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK");
+ result |= fail;
+
+ fail = (((uintptr_t) &g) & (AL - 1)) != 0;
+ printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK");
+ result |= fail;
+
+ result |= in_dso1 ();
+
+ void *h = dlopen ("tst-tlsmod14b.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open tst-tlsmod14b.so: %m\n");
+ exit (1);
+ }
+
+ int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso2");
+ if (fp == NULL)
+ {
+ puts ("cannot find in_dso2");
+ exit (1);
+ }
+
+ result |= fp ();
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-tlsmod14a.c b/elf/tst-tlsmod14a.c
new file mode 100644
index 0000000000..4843e5937e
--- /dev/null
+++ b/elf/tst-tlsmod14a.c
@@ -0,0 +1,36 @@
+#include <stdint.h>
+#include <stdio.h>
+
+
+#define AL 4096
+struct foo
+{
+ int i;
+} __attribute ((aligned (AL)));
+
+static __thread struct foo f;
+static struct foo g;
+
+
+#ifndef FCT
+# define FCT in_dso1
+#endif
+
+
+int
+FCT (void)
+{
+ puts (__func__);
+
+ int result = 0;
+
+ int fail = (((uintptr_t) &f) & (AL - 1)) != 0;
+ printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK");
+ result |= fail;
+
+ fail = (((uintptr_t) &g) & (AL - 1)) != 0;
+ printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK");
+ result |= fail;
+
+ return result;
+}
diff --git a/elf/tst-tlsmod14b.c b/elf/tst-tlsmod14b.c
new file mode 100644
index 0000000000..24d9ceaf7e
--- /dev/null
+++ b/elf/tst-tlsmod14b.c
@@ -0,0 +1,2 @@
+#define FCT in_dso2
+#include "tst-tlsmod14a.c"