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