mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-23 01:33:36 +08:00
Update.
2003-07-24 Ulrich Drepper <drepper@redhat.com> * include/link.h (struct link_map): Add l_tls_firstbyte_offset field. * sysdeps/generic/dl-tls.c [TLS_TCB_AT_TP] (_dl_determine_tlsoffset): Fix calculation of offsets to take misalignment of first byte in file into account. * elf/dl-load.c (_dl_map_object_from_fd): Initialize l_tls_firstbyte_offset field. * elf/rtld.c (_dl_start_final, _dl_start, dl_main): Likewise. * elf/dl-reloc.c (_dl_allocate_static_tls): Change return type to int. Take l_tls_firstbyte_offset information into account. (CHECK_STATIS_TLS): _dl_allocate_static_tls can fail now. * sysdeps/generic/ldsodefs.h: Adjust _dl_allocate_static_tls prototype. * elf/Makefile: Add rules to build and run tst-tls14. * elf/tst-tls14.c: New file. * elf/tst-tlsmod14a.c: New file. * elf/tst-tlsmod14b.c: New file.
This commit is contained in:
parent
6bc0b95489
commit
99fe3b0e7a
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
||||
2003-07-24 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* include/link.h (struct link_map): Add l_tls_firstbyte_offset field.
|
||||
* sysdeps/generic/dl-tls.c [TLS_TCB_AT_TP] (_dl_determine_tlsoffset):
|
||||
Fix calculation of offsets to take misalignment of first byte in
|
||||
file into account.
|
||||
* elf/dl-load.c (_dl_map_object_from_fd): Initialize
|
||||
l_tls_firstbyte_offset field.
|
||||
* elf/rtld.c (_dl_start_final, _dl_start, dl_main): Likewise.
|
||||
* elf/dl-reloc.c (_dl_allocate_static_tls): Change return type to int.
|
||||
Take l_tls_firstbyte_offset information into account.
|
||||
(CHECK_STATIS_TLS): _dl_allocate_static_tls can fail now.
|
||||
* sysdeps/generic/ldsodefs.h: Adjust _dl_allocate_static_tls prototype.
|
||||
* elf/Makefile: Add rules to build and run tst-tls14.
|
||||
* elf/tst-tls14.c: New file.
|
||||
* elf/tst-tlsmod14a.c: New file.
|
||||
* elf/tst-tlsmod14b.c: New file.
|
||||
|
||||
2003-07-23 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* sysdeps/pthread/lio_listio.c (LIO_OPCODE_BASE): Define.
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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"
|
||||
|
11
elf/rtld.c
11
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;
|
||||
|
||||
|
56
elf/tst-tls14.c
Normal file
56
elf/tst-tls14.c
Normal file
@ -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"
|
36
elf/tst-tlsmod14a.c
Normal file
36
elf/tst-tlsmod14a.c
Normal file
@ -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;
|
||||
}
|
2
elf/tst-tlsmod14b.c
Normal file
2
elf/tst-tlsmod14b.c
Normal file
@ -0,0 +1,2 @@
|
||||
#define FCT in_dso2
|
||||
#include "tst-tlsmod14a.c"
|
@ -1,6 +1,6 @@
|
||||
/* Data structure for communication from the run-time dynamic linker for
|
||||
loaded ELF shared objects.
|
||||
Copyright (C) 1995-1999,2000,01,02 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@ -268,6 +268,8 @@ struct link_map
|
||||
size_t l_tls_blocksize;
|
||||
/* Alignment requirement of the TLS block. */
|
||||
size_t l_tls_align;
|
||||
/* Offset of first byte module alignment. */
|
||||
size_t l_tls_firstbyte_offset;
|
||||
# ifndef NO_TLS_OFFSET
|
||||
# define NO_TLS_OFFSET 0
|
||||
# endif
|
||||
|
@ -117,9 +117,10 @@ internal_function
|
||||
_dl_determine_tlsoffset (void)
|
||||
{
|
||||
struct dtv_slotinfo *slotinfo;
|
||||
size_t max_align = __alignof__ (void *);
|
||||
size_t max_align;
|
||||
size_t offset;
|
||||
size_t cnt;
|
||||
size_t freebytes;
|
||||
|
||||
/* The first element of the dtv slot info list is allocated. */
|
||||
assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
|
||||
@ -127,24 +128,78 @@ _dl_determine_tlsoffset (void)
|
||||
dl_tls_dtv_slotinfo_list list. */
|
||||
assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
|
||||
|
||||
/* Determining the offset of the various parts of the static TLS
|
||||
block has several dependencies. In addition we have to work
|
||||
around bugs in some toolchains.
|
||||
|
||||
Each TLS block from the objects available at link time has a size
|
||||
and an alignment requirement. The GNU ld computes the alignment
|
||||
requirements for the data at the positions *in the file*, though.
|
||||
I.e, it is not simply possible to allocate a block with the size
|
||||
of the TLS program header entry. The data is layed out assuming
|
||||
that the first byte of the TLS block fulfills
|
||||
|
||||
p_vaddr mod p_align == &TLS_BLOCK mod p_align
|
||||
|
||||
This means we have to add artificial padding at the beginning of
|
||||
the TLS block. These bytes are never used for the TLS data in
|
||||
this module but the first byte allocated must be aligned
|
||||
according to mod p_align == 0 so that the first byte of the TLS
|
||||
block is aligned according to p_vaddr mod p_align. This is ugly
|
||||
and the linker can help by computing the offsets in the TLS block
|
||||
assuming the first byte of the TLS block is aligned according to
|
||||
p_align.
|
||||
|
||||
We can handle this wrong behavior because of another bug in GNU
|
||||
ld. The p_vaddr field of the TLS segment must be zero (according
|
||||
to the spec) since the linker does not know the address or offset
|
||||
where it will end up at. Once a linker is available which
|
||||
handles the alignment correctly it should set p_addr to zero and
|
||||
all will automatically fall into place.
|
||||
|
||||
The extra space which might be allocated before the first byte of
|
||||
the TLS block need not go unused. The code below tries to use
|
||||
that memory for the next TLS block. This can work if the total
|
||||
memory requirement for the next TLS block is smaller than the
|
||||
gap. */
|
||||
|
||||
# if TLS_TCB_AT_TP
|
||||
/* We simply start with zero. */
|
||||
max_align = __alignof (void *);
|
||||
offset = 0;
|
||||
freebytes = 0;
|
||||
|
||||
slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
|
||||
for (cnt = 1; slotinfo[cnt].map != NULL; ++cnt)
|
||||
{
|
||||
assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
|
||||
|
||||
max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
|
||||
size_t blsize = (slotinfo[cnt].map->l_tls_blocksize
|
||||
+ slotinfo[cnt].map->l_tls_firstbyte_offset);
|
||||
|
||||
/* Compute the offset of the next TLS block. */
|
||||
offset = roundup (offset + slotinfo[cnt].map->l_tls_blocksize,
|
||||
slotinfo[cnt].map->l_tls_align);
|
||||
if (blsize <= freebytes)
|
||||
{
|
||||
/* When we come here the amount of memory we was "wasted"
|
||||
for the correct alignment of the previous block is larger
|
||||
than what we need for this module. So use it. */
|
||||
size_t n = (freebytes - blsize) / slotinfo[cnt].map->l_tls_align;
|
||||
freebytes = (n * slotinfo[cnt].map->l_tls_align
|
||||
+ slotinfo[cnt].map->l_tls_firstbyte_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There is either no gap from the bottom of the static TLS
|
||||
block to the first used byte or the gap is too small.
|
||||
Extend the static TLS block. */
|
||||
offset += roundup (blsize, max_align);
|
||||
freebytes = slotinfo[cnt].map->l_tls_firstbyte_offset;
|
||||
}
|
||||
|
||||
max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
|
||||
|
||||
/* XXX For some architectures we perhaps should store the
|
||||
negative offset. */
|
||||
slotinfo[cnt].map->l_tls_offset = offset;
|
||||
slotinfo[cnt].map->l_tls_offset = offset - freebytes;
|
||||
}
|
||||
|
||||
/* The thread descriptor (pointed to by the thread pointer) has its
|
||||
@ -156,11 +211,12 @@ _dl_determine_tlsoffset (void)
|
||||
// XXX model.
|
||||
|
||||
GL(dl_tls_static_used) = offset;
|
||||
GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS + TLS_TCB_SIZE,
|
||||
TLS_TCB_ALIGN);
|
||||
GL(dl_tls_static_size) = (offset + roundup (TLS_STATIC_SURPLUS, max_align)
|
||||
+ TLS_TCB_SIZE);
|
||||
# elif TLS_DTV_AT_TP
|
||||
/* The TLS blocks start right after the TCB. */
|
||||
offset = TLS_TCB_SIZE;
|
||||
max_align = __alignof (void *);
|
||||
|
||||
/* The first block starts right after the TCB. */
|
||||
slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
|
||||
@ -201,7 +257,7 @@ _dl_determine_tlsoffset (void)
|
||||
# endif
|
||||
|
||||
/* The alignment requirement for the static TLS block. */
|
||||
GL(dl_tls_static_align) = MAX (TLS_TCB_ALIGN, max_align);
|
||||
GL(dl_tls_static_align) = max_align;
|
||||
}
|
||||
|
||||
|
||||
|
@ -797,7 +797,7 @@ rtld_hidden_proto (_dl_allocate_tls)
|
||||
extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
|
||||
internal_function;
|
||||
|
||||
extern void _dl_allocate_static_tls (struct link_map *map)
|
||||
extern int _dl_allocate_static_tls (struct link_map *map)
|
||||
internal_function attribute_hidden;
|
||||
|
||||
/* These are internal entry points to the two halves of _dl_allocate_tls,
|
||||
|
Loading…
Reference in New Issue
Block a user