Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 Jul 2004 12:18:02 GMT
From:      Doug Rabson <dfr@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 57918 for review
Message-ID:  <200407221218.i6MCI2wP099972@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=57918

Change 57918 by dfr@dfr_home on 2004/07/22 12:17:16

	Add support for small amounts of static TLS use by dynamic
	modules. Required for NVidia libGL.

Affected files ...

.. //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#6 edit
.. //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#6 edit
.. //depot/projects/kse/libexec/rtld-elf/ia64/rtld_machdep.h#3 edit
.. //depot/projects/kse/libexec/rtld-elf/map_object.c#4 edit
.. //depot/projects/kse/libexec/rtld-elf/rtld.c#9 edit
.. //depot/projects/kse/libexec/rtld-elf/rtld.h#5 edit

Differences ...

==== //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#6 (text+ko) ====

@@ -239,6 +239,22 @@
 		    if (def == NULL)
 			goto done;
 
+		    /*
+		     * We lazily allocate offsets for static TLS as we
+		     * see the first relocation that references the
+		     * TLS block. This allows us to support (small
+		     * amounts of) static TLS in dynamically loaded
+		     * modules. If we run out of space, we generate an
+		     * error.
+		     */
+		    if (!defobj->tls_done) {
+			if (!allocate_tls_offset((Obj_Entry*) defobj)) {
+			    _rtld_error("%s: No space available for static "
+					"Thread Local Storage", obj->path);
+			    goto done;
+			}
+		    }
+
 		    *where += (Elf_Addr) (def->st_value - defobj->tlsoffset);
 		}
 		break;
@@ -332,6 +348,35 @@
     return 0;
 }
 
+bool
+allocate_tls_offset(Obj_Entry *obj)
+{
+    size_t off;
+
+    if (obj->tlsindex == 1)
+	off = calculate_first_tls_offset(obj->tlssize, obj->tlsalign);
+    else
+	off = calculate_tls_offset(tls_last_offset, tls_last_size,
+				   obj->tlssize, obj->tlsalign);
+
+    /*
+     * If we have already fixed the size of the static TLS block, we
+     * must stay within that size. When allocating the static TLS, we
+     * leave a small amount of space spare to be used for dynamically
+     * loading modules which use static TLS.
+     */
+    if (tls_static_space) {
+	if (calculate_tls_end(off, obj->tlssize) > tls_static_space)
+	    return false;
+    }
+
+    tls_last_offset = obj->tlsoffset = off;
+    tls_last_size = obj->tlssize;
+    obj->tls_done = true;
+
+    return true;
+}
+
 void *
 allocate_tls(Objlist* list, size_t tcbsize, size_t tcbalign)
 {
@@ -340,15 +385,9 @@
     size_t size;
     char *tls;
     Elf_Addr *dtv;
-    Elf_Addr segbase;
+    Elf_Addr segbase, addr;
 
-    size = 0;
-    STAILQ_FOREACH(entry, list, link) {
-	obj = entry->obj;
-        if (obj->tlsoffset > size)
-            size = obj->tlsoffset;
-    }
-    size = round(size, tcbalign);
+    size = round(tls_static_space, tcbalign);
 
     assert(tcbsize >= 2*sizeof(Elf_Addr));
     tls = malloc(size + tcbsize);
@@ -362,12 +401,16 @@
     dtv[1] = tls_max_index;
     STAILQ_FOREACH(entry, list, link) {
 	obj = entry->obj;
-	Elf_Addr addr = segbase - obj->tlsoffset;
-	memset((void*) (addr + obj->tlsinitsize),
-	       0, obj->tlssize - obj->tlsinitsize);
-        if (obj->tlsinit)
-	    memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize);
-	dtv[obj->tlsindex] = addr;
+	if (obj->tlsoffset) {
+	    addr = segbase - obj->tlsoffset;
+	    memset((void*) (addr + obj->tlsinitsize),
+		   0, obj->tlssize - obj->tlsinitsize);
+	    if (obj->tlsinit)
+		memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize);
+	    dtv[obj->tlsindex + 1] = addr;
+	} else if (obj->tlsindex) {
+	    dtv[obj->tlsindex + 1] = 0;
+	}
     }
 
     return (void*) segbase;
@@ -376,8 +419,6 @@
 void
 free_tls(Objlist *list, void *tls, size_t tcbsize, size_t tcbalign)
 {
-    Objlist_Entry *entry;
-    Obj_Entry *obj;
     size_t size;
     Elf_Addr* dtv;
     int dtvsize, i;
@@ -387,13 +428,7 @@
      * Figure out the size of the initial TLS block so that we can
      * find stuff which ___tls_get_addr() allocated dynamically.
      */
-    size = 0;
-    STAILQ_FOREACH(entry, list, link) {
-	obj = entry->obj;
-        if (obj->tlsoffset > size)
-            size = obj->tlsoffset;
-    }
-    size = round(size, tcbalign);
+    size = round(tls_static_space, tcbalign);
 
     dtv = ((Elf_Addr**)tls)[1];
     dtvsize = dtv[1];
@@ -411,10 +446,18 @@
 void
 allocate_initial_tls(Objlist *list)
 {
-    void* tls = allocate_tls(list, 2*sizeof(Elf_Addr), 4);
+    void* tls;
     union descriptor ldt;
     int sel;
 
+    /*
+     * Fix the size of the static TLS block by using the maximum
+     * offset allocated so far and adding a bit for dynamic modules to
+     * use.
+     */
+    tls_static_space = tls_last_offset + 64;
+    tls = allocate_tls(list, 2*sizeof(Elf_Addr), 4);
+
     memset(&ldt, 0, sizeof(ldt));
     ldt.sd.sd_lolimit = 0xffff;	/* 4G limit */
     ldt.sd.sd_lobase = ((Elf_Addr)tls) & 0xffffff;

==== //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#6 (text+ko) ====

@@ -64,6 +64,7 @@
 	round(size, align)
 #define calculate_tls_offset(prev_offset, prev_size, size, align) \
 	round((prev_offset) + (size), align)
+#define calculate_tls_end(off, size) 	(off)
 
 typedef struct {
     unsigned long ti_module;

==== //depot/projects/kse/libexec/rtld-elf/ia64/rtld_machdep.h#3 (text+ko) ====

@@ -61,6 +61,7 @@
 	round(16, align)
 #define calculate_tls_offset(prev_offset, prev_size, size, align) \
 	round(prev_offset + prev_size, align)
+#define calculate_tls_end(off, size) 	((off) + (size))
 
 extern void *__tls_get_addr(unsigned long module, unsigned long offset);
 

==== //depot/projects/kse/libexec/rtld-elf/map_object.c#4 (text+ko) ====

@@ -237,18 +237,9 @@
 	tls_dtv_generation++;
 	obj->tlsindex = ++tls_max_index;
 	obj->tlssize = phtls->p_memsz;
+	obj->tlsalign = phtls->p_align;
 	obj->tlsinitsize = phtls->p_filesz;
 	obj->tlsinit = mapbase + phtls->p_vaddr;
-	if (obj->tlsindex == 1)
-	    obj->tlsoffset = calculate_first_tls_offset(phtls->p_memsz,
-							phtls->p_align);
-	else
-	    obj->tlsoffset = calculate_tls_offset(tls_last_offset,
-						  tls_last_size,
-						  phtls->p_memsz,
-						  phtls->p_align);
-	tls_last_offset = obj->tlsoffset;
-	tls_last_size = obj->tlssize;
     }
     return obj;
 }

==== //depot/projects/kse/libexec/rtld-elf/rtld.c#9 (text+ko) ====

@@ -201,8 +201,9 @@
 /*
  * Globals to control TLS allocation.
  */
-size_t tls_last_offset;		/* TLS offset of last module */
-size_t tls_last_size;		/* TLS size of last module */
+size_t tls_last_offset;		/* Static TLS offset of last module */
+size_t tls_last_size;		/* Static TLS size of last module */
+size_t tls_static_space;	/* Static TLS space allocated */
 int tls_dtv_generation = 1;	/* Used to detect when dtv size changes  */
 int tls_max_index = 1;		/* Largest module index allocated */
 
@@ -751,11 +752,8 @@
 
 	case PT_TLS:
 	    obj->tlsindex = 1;
-	    obj->tlsoffset = calculate_first_tls_offset(ph->p_memsz,
-							ph->p_align);
-	    tls_last_offset = obj->tlsoffset;
-	    tls_last_size = obj->tlssize;
 	    obj->tlssize = ph->p_memsz;
+	    obj->tlsalign = ph->p_align;
 	    obj->tlsinitsize = ph->p_filesz;
 	    obj->tlsinit = (void*) ph->p_vaddr;
 	    break;

==== //depot/projects/kse/libexec/rtld-elf/rtld.h#5 (text+ko) ====

@@ -65,6 +65,7 @@
 
 extern size_t tls_last_offset;
 extern size_t tls_last_size;
+extern size_t tls_static_space;
 extern int tls_dtv_generation;
 extern int tls_max_index;
 
@@ -147,7 +148,8 @@
     void *tlsinit;		/* Base address of TLS init block */
     size_t tlsinitsize;		/* Size of TLS init block for this module */
     size_t tlssize;		/* Size of TLS block for this module */
-    size_t tlsoffset;		/* Offset of TLS block for this module */
+    size_t tlsoffset;		/* Offset of static TLS block for this module */
+    size_t tlsalign;		/* Alignment of static TLS block */
 
     /* Items from the dynamic section. */
     Elf_Addr *pltgot;		/* PLT or GOT, depending on architecture */
@@ -182,6 +184,7 @@
     bool traced;		/* Already printed in ldd trace output */
     bool jmpslots_done;		/* Already have relocated the jump slots */
     bool init_done;		/* Already have added object to init list */
+    bool tls_done;		/* Already allocated offset for static TLS */
 
     struct link_map linkmap;	/* for GDB and dlinfo() */
     Objlist dldags;		/* Object belongs to these dlopened DAGs (%) */
@@ -238,6 +241,7 @@
 int reloc_non_plt(Obj_Entry *, Obj_Entry *);
 int reloc_plt(Obj_Entry *);
 int reloc_jmpslots(Obj_Entry *);
+bool allocate_tls_offset(Obj_Entry *obj);
 void *allocate_tls(Objlist *, size_t, size_t);
 void free_tls(Objlist *, void *, size_t, size_t);
 void allocate_initial_tls(Objlist *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200407221218.i6MCI2wP099972>