PERFORCE change 57918 for review
Doug Rabson
dfr at FreeBSD.org
Thu Jul 22 05:18:03 PDT 2004
http://perforce.freebsd.org/chv.cgi?CH=57918
Change 57918 by dfr at 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 *);
More information about the p4-projects
mailing list