diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/Makefile | 9 | ||||
-rw-r--r-- | elf/dl-load.c | 4 | ||||
-rw-r--r-- | elf/dl-reloc.c | 37 | ||||
-rw-r--r-- | elf/rtld.c | 11 | ||||
-rw-r--r-- | elf/tst-tls14.c | 56 | ||||
-rw-r--r-- | elf/tst-tlsmod14a.c | 36 | ||||
-rw-r--r-- | elf/tst-tlsmod14b.c | 2 |
7 files changed, 144 insertions, 11 deletions
diff --git a/elf/Makefile b/elf/Makefile index 7c654f86ae..bfecc360e2 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -148,7 +148,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ neededtest3 neededtest4 unload2 lateglobal initfirst global \ restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \ circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \ - tst-tls10 tst-tls11 tst-tls12 tst-tls13 + tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 # reldep9 test-srcs = tst-pathopt tests-vis-yes = vismain @@ -171,7 +171,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ tst-tlsmod1 tst-tlsmod2 tst-tlsmod3 tst-tlsmod4 \ tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \ tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \ - tst-tlsmod13 tst-tlsmod13a \ + tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \ circlemod1 circlemod1a circlemod2 circlemod2a \ circlemod3 circlemod3a \ reldep8mod1 reldep8mod2 reldep8mod3 \ @@ -428,6 +428,8 @@ tst-tlsmod8.so-no-z-defs = yes tst-tlsmod9.so-no-z-defs = yes tst-tlsmod10.so-no-z-defs = yes tst-tlsmod12.so-no-z-defs = yes +tst-tlsmod14a.so-no-z-defs = yes +tst-tlsmod14b.so-no-z-defs = yes circlemod2.so-no-z-defs = yes circlemod3.so-no-z-defs = yes circlemod3a.so-no-z-defs = yes @@ -633,6 +635,9 @@ $(objpfx)tst-tls12: $(objpfx)tst-tlsmod12.so $(objpfx)tst-tls13: $(libdl) $(objpfx)tst-tls13.out: $(objpfx)tst-tlsmod13a.so +$(objpfx)tst-tls14: $(objpfx)tst-tlsmod14a.so $(libdl) +$(objpfx)tst-tls14.out:$(objpfx)tst-tlsmod14b.so + ifdef libdl $(objpfx)tst-tls9-static: $(common-objpfx)dlfcn/libdl.a $(objpfx)tst-tls9-static.out: $(objpfx)tst-tlsmod5.so $(objpfx)tst-tlsmod6.so diff --git a/elf/dl-load.c b/elf/dl-load.c index f3c9e82423..249ef84639 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -987,6 +987,10 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp, l->l_tls_blocksize = ph->p_memsz; l->l_tls_align = ph->p_align; + if (ph->p_align == 0) + l->l_tls_firstbyte_offset = 0; + else + l->l_tls_firstbyte_offset = ph->p_vaddr & (ph->p_align - 1); l->l_tls_initimage_size = ph->p_filesz; /* Since we don't know the load address yet only store the offset. We will adjust it later. */ diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 6165fe4aca..d82ea108d0 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -41,27 +41,39 @@ the static TLS area already allocated for each running thread. If this object's TLS segment is too big to fit, we fail. If it fits, we set MAP->l_tls_offset and return. */ -void +int internal_function __attribute_noinline__ _dl_allocate_static_tls (struct link_map *map) { size_t offset; size_t used; size_t check; + size_t freebytes; + size_t n; + size_t blsize; + + /* If the alignment requirements are too high fail. */ + if (map->l_tls_align > GL(dl_tls_static_align)) + return 1; # if TLS_TCB_AT_TP - offset = roundup (GL(dl_tls_static_used) + map->l_tls_blocksize, - map->l_tls_align); - used = offset; - check = offset + TLS_TCB_SIZE; + freebytes = GL(dl_tls_static_size) - GL(dl_tls_static_used) - TLS_TCB_SIZE; + + blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset; + if (freebytes < blsize) + return 1; + + n = (freebytes - blsize) / map->l_tls_align; + + offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align + - map->l_tls_firstbyte_offset); + + map->l_tls_offset = GL(dl_tls_static_used) = offset; # elif TLS_DTV_AT_TP offset = roundup (GL(dl_tls_static_used), map->l_tls_align); used = offset + map->l_tls_blocksize; check = used; /* dl_tls_static_used includes the TCB at the beginning. */ -# else -# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" -# endif if (check > GL(dl_tls_static_size)) { @@ -72,6 +84,11 @@ shared object cannot be dlopen()ed: static TLS memory too small"); map->l_tls_offset = offset; GL(dl_tls_static_used) = used; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + return 0; } #endif @@ -212,7 +229,9 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], #define CHECK_STATIC_TLS(map, sym_map) \ do { \ if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \ - _dl_allocate_static_tls (sym_map); \ + if (_dl_allocate_static_tls (sym_map) != 0) \ + INTUSE(_dl_signal_error) (0, sym_map->l_name, NULL, N_("\ +cannot allocate memory in static TLS block")); \ } while (0) #include "dynamic-link.h" diff --git a/elf/rtld.c b/elf/rtld.c index 4a086c2d32..c63405ac99 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -227,6 +227,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) assert (info->l.l_tls_modid != 0); GL(dl_rtld_map).l_tls_blocksize = info->l.l_tls_blocksize; GL(dl_rtld_map).l_tls_align = info->l.l_tls_align; + GL(dl_rtld_map).l_tls_firstbyte_offset = info->l.l_tls_firstbyte_offset; GL(dl_rtld_map).l_tls_initimage_size = info->l.l_tls_initimage_size; GL(dl_rtld_map).l_tls_initimage = info->l.l_tls_initimage; GL(dl_rtld_map).l_tls_offset = info->l.l_tls_offset; @@ -347,6 +348,11 @@ _dl_start (void *arg) bootstrap_map.l_tls_blocksize = phdr[cnt].p_memsz; bootstrap_map.l_tls_align = phdr[cnt].p_align; + if (phdr[cnt].p_align == 0) + bootstrap_map.l_tls_firstbyte_offset = 0; + else + bootstrap_map.l_tls_firstbyte_offset = (phdr[cnt].p_vaddr + & (phdr[cnt].p_align - 1)); assert (bootstrap_map.l_tls_blocksize != 0); bootstrap_map.l_tls_initimage_size = phdr[cnt].p_filesz; bootstrap_map.l_tls_initimage = (void *) (bootstrap_map.l_addr @@ -860,6 +866,11 @@ of this helper program; chances are you did not intend to run this program.\n\ check for this special but unimportant case. */ GL(dl_loaded)->l_tls_blocksize = ph->p_memsz; GL(dl_loaded)->l_tls_align = ph->p_align; + if (ph->p_align == 0) + GL(dl_loaded)->l_tls_firstbyte_offset = 0; + else + GL(dl_loaded)->l_tls_firstbyte_offset = (ph->p_vaddr + & (ph->p_align - 1)); GL(dl_loaded)->l_tls_initimage_size = ph->p_filesz; GL(dl_loaded)->l_tls_initimage = (void *) ph->p_vaddr; diff --git a/elf/tst-tls14.c b/elf/tst-tls14.c new file mode 100644 index 0000000000..4ae367a38f --- /dev/null +++ b/elf/tst-tls14.c @@ -0,0 +1,56 @@ +/* Check alignment of TLS variable. */ +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + + +#define AL 4096 +struct foo +{ + int i; +} __attribute ((aligned (AL))); + +static __thread struct foo f; +static struct foo g; + + +extern int in_dso1 (void); + + +static int +do_test (void) +{ + int result = 0; + + int fail = (((uintptr_t) &f) & (AL - 1)) != 0; + printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK"); + result |= fail; + + fail = (((uintptr_t) &g) & (AL - 1)) != 0; + printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK"); + result |= fail; + + result |= in_dso1 (); + + void *h = dlopen ("tst-tlsmod14b.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open tst-tlsmod14b.so: %m\n"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso2"); + if (fp == NULL) + { + puts ("cannot find in_dso2"); + exit (1); + } + + result |= fp (); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/elf/tst-tlsmod14a.c b/elf/tst-tlsmod14a.c new file mode 100644 index 0000000000..4843e5937e --- /dev/null +++ b/elf/tst-tlsmod14a.c @@ -0,0 +1,36 @@ +#include <stdint.h> +#include <stdio.h> + + +#define AL 4096 +struct foo +{ + int i; +} __attribute ((aligned (AL))); + +static __thread struct foo f; +static struct foo g; + + +#ifndef FCT +# define FCT in_dso1 +#endif + + +int +FCT (void) +{ + puts (__func__); + + int result = 0; + + int fail = (((uintptr_t) &f) & (AL - 1)) != 0; + printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK"); + result |= fail; + + fail = (((uintptr_t) &g) & (AL - 1)) != 0; + printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK"); + result |= fail; + + return result; +} diff --git a/elf/tst-tlsmod14b.c b/elf/tst-tlsmod14b.c new file mode 100644 index 0000000000..24d9ceaf7e --- /dev/null +++ b/elf/tst-tlsmod14b.c @@ -0,0 +1,2 @@ +#define FCT in_dso2 +#include "tst-tlsmod14a.c" |