summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libexec/rtld-elf/map_object.c3
-rw-r--r--libexec/rtld-elf/rtld.c20
-rw-r--r--libexec/rtld-elf/rtld.h1
3 files changed, 24 insertions, 0 deletions
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index 33fb9a6..2b1ef24 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -305,6 +305,9 @@ obj_free(Obj_Entry *obj)
{
Objlist_Entry *elm;
+ if (obj->tls_done) {
+ free_tls_offset(obj);
+ }
free(obj->path);
while (obj->needed != NULL) {
Needed_Entry *needed = obj->needed;
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 6fc64dd..aec6e3d 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -2773,6 +2773,26 @@ allocate_tls_offset(Obj_Entry *obj)
return true;
}
+void
+free_tls_offset(Obj_Entry *obj)
+{
+#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \
+ defined(__arm__)
+ /*
+ * If we were the last thing to allocate out of the static TLS
+ * block, we give our space back to the 'allocator'. This is a
+ * simplistic workaround to allow libGL.so.1 to be loaded and
+ * unloaded multiple times. We only handle the Variant II
+ * mechanism for now - this really needs a proper allocator.
+ */
+ if (calculate_tls_end(obj->tlsoffset, obj->tlssize)
+ == calculate_tls_end(tls_last_offset, tls_last_size)) {
+ tls_last_offset -= obj->tlssize;
+ tls_last_size = 0;
+ }
+#endif
+}
+
void *
_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
{
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index 69964d6..bee36af 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -238,6 +238,7 @@ void *allocate_tls(Obj_Entry *, void *, size_t, size_t);
void free_tls(void *, size_t, size_t);
void *allocate_module_tls(int index);
bool allocate_tls_offset(Obj_Entry *obj);
+void free_tls_offset(Obj_Entry *obj);
/*
* MD function declarations.
OpenPOWER on IntegriCloud