PERFORCE change 50112 for review

Doug Rabson dfr at FreeBSD.org
Thu Apr 1 01:16:42 PST 2004


http://perforce.freebsd.org/chv.cgi?CH=50112

Change 50112 by dfr at dfr_home on 2004/04/01 01:16:06

	Prototype TLS support in rtld (i386 only to start with).

Affected files ...

.. //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#2 edit
.. //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#2 edit
.. //depot/projects/kse/libexec/rtld-elf/map_object.c#2 edit
.. //depot/projects/kse/libexec/rtld-elf/rtld.c#2 edit
.. //depot/projects/kse/libexec/rtld-elf/rtld.h#2 edit

Differences ...

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

@@ -33,6 +33,8 @@
 
 #include <sys/param.h>
 #include <sys/mman.h>
+#include <machine/segments.h>
+#include <machine/sysarch.h>
 
 #include <dlfcn.h>
 #include <err.h>
@@ -47,6 +49,31 @@
 #include "debug.h"
 #include "rtld.h"
 
+#ifndef R_386_TLS_TPOFF
+
+#define R_386_TLS_TPOFF		14
+#define R_386_TLS_IE		15
+#define R_386_TLS_GOTIE		16
+#define R_386_TLS_LE		17
+#define R_386_TLS_GD		18
+#define R_386_TLS_LDM		19
+#define R_386_TLS_GD_32		24
+#define R_386_TLS_GD_PUSH	25
+#define R_386_TLS_GD_CALL	26
+#define R_386_TLS_GD_POP	27
+#define R_386_TLS_LDM_32	28
+#define R_386_TLS_LDM_PUSH	29
+#define R_386_TLS_LDM_CALL	30
+#define R_386_TLS_LDM_POP	31
+#define R_386_TLS_LDO_32	32
+#define R_386_TLS_IE_32		33
+#define R_386_TLS_LE_32		34
+#define R_386_TLS_DTPMOD32	35
+#define R_386_TLS_DTPOFF32	36
+#define R_386_TLS_TPOFF32	37
+
+#endif
+
 /*
  * Process the special R_386_COPY relocations in the main program.  These
  * copy data from a shared object into a region in the main program's BSS
@@ -202,6 +229,48 @@
 		*where += (Elf_Addr) obj->relocbase;
 		break;
 
+	    case R_386_TLS_TPOFF:
+		{
+		    const Elf_Sym *def;
+		    const Obj_Entry *defobj;
+
+		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
+		      false, cache);
+		    if (def == NULL)
+			goto done;
+
+		    *where += (Elf_Addr) (def->st_value - defobj->tlsoffset);
+		}
+		break;
+
+	    case R_386_TLS_DTPMOD32:
+		{
+		    const Elf_Sym *def;
+		    const Obj_Entry *defobj;
+
+		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
+		      false, cache);
+		    if (def == NULL)
+			goto done;
+
+		    *where += (Elf_Addr) defobj->tlsindex;
+		}
+		break;
+
+	    case R_386_TLS_DTPOFF32:
+		{
+		    const Elf_Sym *def;
+		    const Obj_Entry *defobj;
+
+		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
+		      false, cache);
+		    if (def == NULL)
+			goto done;
+
+		    *where += (Elf_Addr) def->st_value;
+		}
+		break;
+
 	    default:
 		_rtld_error("%s: Unsupported relocation type %d"
 		  " in non-PLT relocations\n", obj->path,
@@ -262,3 +331,76 @@
     obj->jmpslots_done = true;
     return 0;
 }
+
+void
+allocate_initial_tls(Obj_Entry *list)
+{
+    Obj_Entry *obj;
+    size_t size;
+    char *tls;
+    Elf_Addr *dtv;
+    union descriptor ldt;
+    Elf_Addr segbase;
+    int sel;
+
+    size = 0;
+    for (obj = list; obj; obj = obj->next) {
+        if (obj->tlsoffset > size)
+            size = obj->tlsoffset;
+    }
+
+    tls = malloc(size + 2*sizeof(Elf_Addr));
+    dtv = malloc((tls_max_index + 2) * sizeof(Elf_Addr));
+
+    segbase = (Elf_Addr)(tls + size);
+    ((Elf_Addr*)segbase)[0] = segbase;
+    ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
+
+    dtv[0] = tls_dtv_generation;
+    dtv[1] = tls_max_index;
+    for (obj = list; obj; obj = obj->next) {
+	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;
+    }
+
+    memset(&ldt, 0, sizeof(ldt));
+    ldt.sd.sd_lolimit = 4;
+    ldt.sd.sd_lobase = segbase & 0xffffff;
+    ldt.sd.sd_type = SDT_MEMRWA;
+    ldt.sd.sd_dpl = SEL_UPL;
+    ldt.sd.sd_p = 1;		/* present */
+    ldt.sd.sd_hilimit = 0;
+    ldt.sd.sd_def32 = 1;	/* 32 bit */
+    ldt.sd.sd_gran = 0;		/* limit in bytes */
+    ldt.sd.sd_hibase = (segbase >> 24) & 0xff;
+    sel = i386_set_ldt(LDT_AUTO_ALLOC, &ldt, 1);
+    __asm __volatile("movl %0,%%gs" : : "rm" ((sel << 3) | 7));
+}
+
+/* GNU ABI */
+void *___tls_get_addr(tls_index *ti)
+{
+    Elf_Addr** segbase;
+    Elf_Addr* dtv;
+
+    __asm __volatile("movl %%gs:0, %0" : "=r" (segbase));
+    dtv = segbase[1];
+
+    return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset);
+}
+
+/* Sun ABI */
+void *__tls_get_addr(tls_index *ti)
+{
+    Elf_Addr** segbase;
+    Elf_Addr* dtv;
+
+    __asm __volatile("movl %%gs:0, %0" : "=r" (segbase));
+    dtv = segbase[1];
+
+    return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset);
+}

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

@@ -58,4 +58,16 @@
 #define call_initfini_pointer(obj, target) \
 	(((InitFunc)(target))())
 
+#define calculate_tls_offset(prev_offset, size, align) \
+	(((prev_offset) + (size) + ((1 << (align)) - 1)) \
+	    & ~((1 << (align)) - 1))
+
+typedef struct {
+    unsigned long ti_module;
+    unsigned long ti_offset;
+} tls_index;
+
+extern void *___tls_get_addr(tls_index *ti) __attribute__((__regparm__(1)));
+extern void *__tls_get_addr(tls_index *ti);
+
 #endif

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

@@ -63,6 +63,7 @@
     Elf_Phdr *phdyn;
     Elf_Phdr *phphdr;
     Elf_Phdr *phinterp;
+    Elf_Phdr *phtls;
     caddr_t mapbase;
     size_t mapsize;
     Elf_Off base_offset;
@@ -96,7 +97,7 @@
     phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff);
     phlimit = phdr + hdr->e_phnum;
     nsegs = -1;
-    phdyn = phphdr = phinterp = NULL;
+    phdyn = phphdr = phinterp = phtls = NULL;
     segs = alloca(sizeof(segs[0]) * hdr->e_phnum);
     while (phdr < phlimit) {
 	switch (phdr->p_type) {
@@ -121,6 +122,10 @@
 	case PT_DYNAMIC:
 	    phdyn = phdr;
 	    break;
+
+	case PT_TLS:
+	    phtls = phdr;
+	    break;
 	}
 
 	++phdr;
@@ -228,7 +233,16 @@
     }
     if (phinterp != NULL)
 	obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr);
-
+    if (phtls != NULL) {
+	tls_dtv_generation++;
+	obj->tlsindex = ++tls_max_index;
+	obj->tlssize = phtls->p_memsz;
+	obj->tlsinitsize = phtls->p_filesz;
+	obj->tlsinit = mapbase + phtls->p_vaddr;
+	obj->tlsoffset = calculate_tls_offset(tls_last_offset,
+					      phtls->p_memsz, phtls->p_align);
+	tls_last_offset = obj->tlsoffset;
+    }
     return obj;
 }
 

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

@@ -178,6 +178,9 @@
     (func_ptr_type) &dllockinit,
     (func_ptr_type) &dlinfo,
     (func_ptr_type) &_rtld_thread_init,
+#ifdef __i386__
+    (func_ptr_type) &___tls_get_addr,
+#endif
     NULL
 };
 
@@ -189,6 +192,13 @@
 char **environ;
 
 /*
+ * Globals to control TLS allocation.
+ */
+size_t tls_last_offset;		/* TLS offset of last module */
+int tls_dtv_generation = 1;	/* Used to detect when dtv size changes  */
+int tls_max_index = 1;		/* Largest module index allocated */
+
+/*
  * Fill in a DoneList with an allocation large enough to hold all of
  * the currently-loaded objects.  Keep this as a macro since it calls
  * alloca and we want that to occur within the scope of the caller.
@@ -390,6 +400,12 @@
     dbg("initializing thread locks");
     lockdflt_init();
 
+    /* setup TLS for main thread */
+    dbg("initializing initial thread local storage (size %d)",
+	tls_last_offset);
+    allocate_initial_tls(obj_list);
+    dbg("foo");
+
     /* Make a list of init functions to call. */
     objlist_init(&initlist);
     initlist_add_objects(obj_list, preload_tail, &initlist);
@@ -726,6 +742,15 @@
 	case PT_DYNAMIC:
 	    obj->dynamic = (const Elf_Dyn *) ph->p_vaddr;
 	    break;
+
+	case PT_TLS:
+	    obj->tlsindex = 1;
+	    obj->tlsoffset = calculate_tls_offset(0, ph->p_memsz,
+						  ph->p_align);
+	    tls_last_offset = obj->tlsoffset;
+	    obj->tlsinitsize = ph->p_filesz;
+	    obj->tlsinit = (void*) ph->p_vaddr;
+	    break;
 	}
     }
     if (nsegs < 1) {
@@ -2433,4 +2458,58 @@
 	elm->obj->refcount--;
 }
 
+/*
+ * Common code for MD __tls_get_addr().
+ */
+void *
+tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset)
+{
+    Elf_Addr* dtv = *dtvp;
+
+    /* Check dtv generation in case new modules have arrived */
+    if (dtv[0] != tls_dtv_generation) {
+	Elf_Addr* newdtv;
+	int to_copy;
 
+	newdtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr));
+	to_copy = dtv[1];
+	if (to_copy > tls_max_index)
+	    to_copy = tls_max_index;
+	memcpy(&newdtv[2], &dtv[2], to_copy * sizeof(Elf_Addr));
+	newdtv[0] = tls_dtv_generation;
+	newdtv[1] = tls_max_index;
+	free(dtv);
+	*dtvp = newdtv;
+    }
+
+    /* Dynamically allocate module TLS if necessary */
+    if (!dtv[index + 1])
+	dtv[index + 1] = (Elf_Addr)allocate_tls(index);
+
+    return (void*) (dtv[index + 1] + offset);
+}
+
+/*
+ * Allocate TLS block for module with given index.
+ */
+void *
+allocate_tls(int index)
+{
+    Obj_Entry* obj;
+    char* p;
+
+    for (obj = obj_list; obj; obj = obj->next) {
+	if (obj->tlsindex == index)
+	    break;
+    }
+    if (!obj) {
+	_rtld_error("Can't find module with TLS index %d", index);
+	die();
+    }
+
+    p = malloc(obj->tlssize);
+    memcpy(p, obj->tlsinit, obj->tlsinitsize);
+    memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize);
+
+    return p;
+}

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

@@ -63,6 +63,10 @@
 #define false	0
 #define true	1
 
+extern size_t tls_last_offset;
+extern int tls_dtv_generation;
+extern int tls_max_index;
+
 struct stat;
 struct Struct_Obj_Entry;
 
@@ -137,6 +141,13 @@
     size_t phsize;		/* Size of program header in bytes */
     const char *interp;		/* Pathname of the interpreter, if any */
 
+    /* TLS information */
+    int tlsindex;		/* Index in DTV for this module */
+    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 */
+
     /* Items from the dynamic section. */
     Elf_Addr *pltgot;		/* PLT or GOT, depending on architecture */
     const Elf_Rel *rel;		/* Relocation entries */
@@ -216,6 +227,8 @@
 void _rtld_bind_start(void);
 const Elf_Sym *symlook_obj(const char *, unsigned long,
   const Obj_Entry *, bool);
+void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset);
+void *allocate_tls(int index);
 
 /*
  * MD function declarations.
@@ -224,5 +237,6 @@
 int reloc_non_plt(Obj_Entry *, Obj_Entry *);
 int reloc_plt(Obj_Entry *);
 int reloc_jmpslots(Obj_Entry *);
+void allocate_initial_tls(Obj_Entry *);
 
 #endif /* } */


More information about the p4-projects mailing list