about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile7
-rw-r--r--elf/dl-close.c51
-rw-r--r--elf/dl-reloc.c4
-rw-r--r--elf/tst-tls8.c8
-rw-r--r--elf/tst-tlsmod13.c14
-rw-r--r--elf/tst-tlsmod13a.c16
6 files changed, 91 insertions, 9 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 3838a11c28..c557bd8f37 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -145,7 +145,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-tls10 tst-tls11 tst-tls12 tst-tls13
 #	 reldep9
 test-srcs = tst-pathopt
 tests-vis-yes = vismain
@@ -168,6 +168,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 \
 		circlemod1 circlemod1a circlemod2 circlemod2a \
 		circlemod3 circlemod3a \
 		reldep8mod1 reldep8mod2 reldep8mod3 \
@@ -383,6 +384,7 @@ $(objpfx)tst-tlsmod3.so: $(objpfx)tst-tlsmod2.so
 $(objpfx)tst-tlsmod8.so: $(objpfx)tst-tlsmod7.so
 $(objpfx)tst-tlsmod10.so: $(objpfx)tst-tlsmod9.so
 $(objpfx)tst-tlsmod12.so: $(objpfx)tst-tlsmod11.so
+$(objpfx)tst-tlsmod13a.so: $(objpfx)tst-tlsmod13.so
 # For tst-tls9-static, make sure the modules it dlopens have libc.so in DT_NEEDED
 $(objpfx)tst-tlsmod5.so: $(common-objpfx)libc.so
 $(objpfx)tst-tlsmod6.so: $(common-objpfx)libc.so
@@ -590,6 +592,9 @@ $(objpfx)tst-tls11: $(objpfx)tst-tlsmod10.so
 
 $(objpfx)tst-tls12: $(objpfx)tst-tlsmod12.so
 
+$(objpfx)tst-tls13: $(libdl)
+$(objpfx)tst-tls13.out: $(objpfx)tst-tlsmod13a.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-close.c b/elf/dl-close.c
index 78b143f8ec..b482e89f13 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -321,8 +321,9 @@ _dl_close (void *_map)
   _dl_debug_state ();
 
 #ifdef USE_TLS
-  size_t tls_free_start, tls_free_end;
-  tls_free_start = tls_free_end = GL(dl_tls_static_used);
+  size_t tls_free_start;
+  size_t tls_free_end;
+  tls_free_start = tls_free_end = NO_TLS_OFFSET;
 #endif
 
   /* Check each element of the search list to see if all references to
@@ -371,9 +372,50 @@ _dl_close (void *_map)
 		     this search list, going in either direction.  When the
 		     whole chunk is at the end of the used area then we can
 		     reclaim it.  */
+# if TLS_TCB_AT_TP
+		  if (tls_free_start == NO_TLS_OFFSET
+		      || (size_t) imap->l_tls_offset == tls_free_start)
+		    {
+		      /* Extend the contiguous chunk being reclaimed.  */
+		      tls_free_start
+			= imap->l_tls_offset - imap->l_tls_blocksize;
+
+		      if (tls_free_end == NO_TLS_OFFSET)
+			tls_free_end = imap->l_tls_offset;
+		    }
+		  else if (imap->l_tls_offset - imap->l_tls_blocksize
+			   == tls_free_end)
+		    /* Extend the chunk backwards.  */
+		    tls_free_end = imap->l_tls_offset;
+		  else
+		    {
+		      /* This isn't contiguous with the last chunk freed.
+			 One of them will be leaked unless we can free
+			 one block right away.  */
+		      if (tls_free_end == GL(dl_tls_static_used))
+			{
+			  GL(dl_tls_static_used) = tls_free_start;
+			  tls_free_end = imap->l_tls_offset;
+			  tls_free_start
+			    = tls_free_end - imap->l_tls_blocksize;
+			}
+		      else if ((size_t) imap->l_tls_offset
+			       == GL(dl_tls_static_used))
+			GL(dl_tls_static_used)
+			  = imap->l_tls_offset - imap->l_tls_blocksize;
+		      else if (tls_free_end < (size_t) imap->l_tls_offset)
+			{
+			  /* We pick the later block.  It has a chance to
+			     be freed.  */
+			  tls_free_end = imap->l_tls_offset;
+			  tls_free_start
+			    = tls_free_end - imap->l_tls_blocksize;
+			}
+		    }
+# elif TLS_DTV_AT_TP
 		  if ((size_t) imap->l_tls_offset == tls_free_end)
 		    /* Extend the contiguous chunk being reclaimed.  */
-		    tls_free_end += imap->l_tls_blocksize;
+		    tls_free_end -= imap->l_tls_blocksize;
 		  else if (imap->l_tls_offset + imap->l_tls_blocksize
 			   == tls_free_start)
 		    /* Extend the chunk backwards.  */
@@ -387,6 +429,9 @@ _dl_close (void *_map)
 		      tls_free_start = imap->l_tls_offset;
 		      tls_free_end = tls_free_start + imap->l_tls_blocksize;
 		    }
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
 		}
 	    }
 #endif
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index c7f1f3417f..6165fe4aca 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -45,7 +45,9 @@ void
 internal_function __attribute_noinline__
 _dl_allocate_static_tls (struct link_map *map)
 {
-  size_t offset, used, check;
+  size_t offset;
+  size_t used;
+  size_t check;
 
 # if TLS_TCB_AT_TP
   offset = roundup (GL(dl_tls_static_used) + map->l_tls_blocksize,
diff --git a/elf/tst-tls8.c b/elf/tst-tls8.c
index e300bc53d8..97b4a25652 100644
--- a/elf/tst-tls8.c
+++ b/elf/tst-tls8.c
@@ -19,8 +19,8 @@ do_test (void)
   void *h1;
   void *h2;
   int i;
-  int modid1 = -1;
-  int modid2 = -1;
+  size_t modid1 = (size_t) -1;
+  size_t modid2 = (size_t) -1;
   int *bazp;
 
   for (i = 0; i < 10; ++i)
@@ -35,7 +35,7 @@ do_test (void)
       /* Dirty test code here: we peek into a private data structure.
 	 We make sure that the module gets assigned the same ID every
 	 time.  The value of the first round is used.  */
-      if (modid1 == -1)
+      if (modid1 == (size_t) -1)
 	modid1 = ((struct link_map *) h1)->l_tls_modid;
       else if (((struct link_map *) h1)->l_tls_modid != modid1)
 	{
@@ -65,7 +65,7 @@ do_test (void)
       /* Dirty test code here: we peek into a private data structure.
 	 We make sure that the module gets assigned the same ID every
 	 time.  The value of the first round is used.  */
-      if (modid2 == -1)
+      if (modid2 == (size_t) -1)
 	modid2 = ((struct link_map *) h1)->l_tls_modid;
       else if (((struct link_map *) h1)->l_tls_modid != modid2)
 	{
diff --git a/elf/tst-tlsmod13.c b/elf/tst-tlsmod13.c
new file mode 100644
index 0000000000..beca89f6fe
--- /dev/null
+++ b/elf/tst-tlsmod13.c
@@ -0,0 +1,14 @@
+#include <tls.h>
+
+#if defined USE_TLS && defined HAVE___THREAD \
+    && defined HAVE_TLS_MODEL_ATTRIBUTE
+__thread int a[2] __attribute__ ((tls_model ("initial-exec")));
+#else
+int a[2];
+#endif
+
+int
+foo (void)
+{
+  return a[0];
+}
diff --git a/elf/tst-tlsmod13a.c b/elf/tst-tlsmod13a.c
new file mode 100644
index 0000000000..14b12b032b
--- /dev/null
+++ b/elf/tst-tlsmod13a.c
@@ -0,0 +1,16 @@
+#include <tls.h>
+
+#if defined USE_TLS && defined HAVE___THREAD \
+    && defined HAVE_TLS_MODEL_ATTRIBUTE
+__thread int b[2] __attribute__ ((tls_model ("initial-exec")));
+#else
+int b[2];
+#endif
+
+extern int foo (void);
+
+int
+bar (void)
+{
+  return foo () + b[0];
+}