about summary refs log tree commit diff
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"