From: Michael Jeanson <mjeanson@efficios.com>
To: libc-alpha@sourceware.org
Cc: Michael Jeanson <mjeanson@efficios.com>,
Florian Weimer <fweimer@redhat.com>,
Carlos O'Donell <carlos@redhat.com>, DJ Delorie <dj@redhat.com>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Subject: [PATCH v16 2/8] Add generic 'extra TLS'
Date: Thu, 9 Jan 2025 16:32:09 +0000 [thread overview]
Message-ID: <20250109163215.2343659-3-mjeanson@efficios.com> (raw)
In-Reply-To: <20250109163215.2343659-1-mjeanson@efficios.com>
Add the logic to append an 'extra TLS' block in the TLS block allocator
with a generic stub implementation. The duplicated code in
'csu/libc-tls.c' and 'elf/dl-tls.c' is to handle both statically linked
applications and the ELF dynamic loader.
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
---
Changes since v15:
- Improve comments around size and alignment calculations
- Simplify tls_blocks_size calculations
- Make sure we don't roundup to zero alignment
Changes since v14:
- Add TLS_TP_OFFSET to the extra TLS block offset calculation
- Style nits
- Update copyright year to 2025
Changes since v13:
- Improve commit message
---
csu/libc-tls.c | 82 ++++++++++++++++++++++++++++++----
elf/dl-tls.c | 72 +++++++++++++++++++++++++++++
| 46 +++++++++++++++++++
3 files changed, 191 insertions(+), 9 deletions(-)
create mode 100644 sysdeps/generic/dl-extra_tls.h
diff --git a/csu/libc-tls.c b/csu/libc-tls.c
index 15f470aa87..02855d0b54 100644
--- a/csu/libc-tls.c
+++ b/csu/libc-tls.c
@@ -20,12 +20,14 @@
#include <errno.h>
#include <ldsodefs.h>
#include <tls.h>
+#include <dl-tls.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/param.h>
#include <array_length.h>
#include <pthreadP.h>
#include <dl-call_tls_init_tp.h>
+#include <dl-extra_tls.h>
#ifdef SHARED
#error makefile bug, this file is for static only
@@ -110,6 +112,7 @@ __libc_setup_tls (void)
size_t filesz = 0;
void *initimage = NULL;
size_t align = 0;
+ size_t tls_blocks_size = 0;
size_t max_align = TCB_ALIGNMENT;
size_t tcb_offset;
const ElfW(Phdr) *phdr;
@@ -135,22 +138,89 @@ __libc_setup_tls (void)
/* Calculate the size of the static TLS surplus, with 0 auditors. */
_dl_tls_static_surplus_init (0);
+ /* Extra TLS block for internal usage to append at the end of the TLS blocks
+ (in allocation order). The address at which the block is allocated must
+ be aligned to 'extra_tls_align'. The size of the block as returned by
+ '_dl_extra_tls_get_size ()' is always a multiple of the aligment.
+
+ On Linux systems this is where the rseq area will be allocated. On other
+ systems it is currently unused and both values will be '0'. */
+ size_t extra_tls_size = _dl_extra_tls_get_size ();
+ size_t extra_tls_align = _dl_extra_tls_get_align ();
+
+ /* Increase the maximum alignment with the extra TLS alignment requirements
+ if necessary. */
+ max_align = MAX (max_align, extra_tls_align);
+
/* We have to set up the TCB block which also (possibly) contains
'errno'. Therefore we avoid 'malloc' which might touch 'errno'.
Instead we use 'sbrk' which would only uses 'errno' if it fails.
In this case we are right away out of memory and the user gets
what she/he deserves. */
#if TLS_TCB_AT_TP
+ /* In this layout the TLS blocks are located before the thread pointer. */
+
+ /* Record the size of the combined TLS blocks.
+
+ First reserve space for 'memsz' while respecting both its alignment
+ requirements and those of the extra TLS blocks. Then add the size of
+ the extra TLS block. Both values respect the extra TLS alignment
+ requirements and so does the resulting size and the offset that will
+ be derived from it. */
+ tls_blocks_size = roundup (memsz, MAX (align, extra_tls_align) ?: 1)
+ + extra_tls_size;
+
+ /* Record the extra TLS block offset from the thread pointer.
+
+ With TLS_TCB_AT_TP the TLS blocks are allocated before the thread pointer
+ in reverse order. Our block is added last which results in it being the
+ first in the static TLS block, thus record the most negative offset.
+
+ The alignment requirements of the pointer resulting from this offset and
+ the thread pointer are enforced by 'max_align' which is used to align the
+ tcb_offset. */
+ _dl_extra_tls_set_offset (-tls_blocks_size);
+
/* Align the TCB offset to the maximum alignment, as
_dl_allocate_tls_storage (in elf/dl-tls.c) does using __libc_memalign
and dl_tls_static_align. */
- tcb_offset = roundup (memsz + GLRO(dl_tls_static_surplus), max_align);
+ tcb_offset = roundup (tls_blocks_size + GLRO(dl_tls_static_surplus), max_align);
tlsblock = _dl_early_allocate (tcb_offset + TLS_INIT_TCB_SIZE + max_align);
if (tlsblock == NULL)
_startup_fatal_tls_error ();
#elif TLS_DTV_AT_TP
+ /* In this layout the TLS blocks are located after the thread pointer. */
+
+ /* Record the tcb_offset including the aligment requirements of 'memsz'
+ that comes after it. */
tcb_offset = roundup (TLS_INIT_TCB_SIZE, align ?: 1);
- tlsblock = _dl_early_allocate (tcb_offset + memsz + max_align
+
+ /* Record the size of the combined TLS blocks.
+
+ First reserve space for TLS_INIT_TCB_SIZE and 'memsz' while respecting
+ both its alignment requirements and those of the extra TLS blocks. Then
+ add the size of the extra TLS block. Both values respect the extra TLS
+ alignment requirements and so does the resulting size and the offset that
+ will be derived from it. */
+ tls_blocks_size = roundup (TLS_INIT_TCB_SIZE + memsz,
+ MAX (align, extra_tls_align) ?: 1) + extra_tls_size;
+
+ /* Record the extra TLS block offset from the thread pointer.
+
+ With TLS_DTV_AT_TP the TLS blocks are allocated after the thread pointer in
+ order. Our block is added last which results in it being the last in the
+ static TLS block, thus record the offset as the size of the static TLS
+ block minus the size of our block.
+
+ On some architectures the TLS blocks are offset from the thread pointer,
+ include this offset in the extra TLS block offset.
+
+ The alignment requirements of the pointer resulting from this offset and
+ the thread pointer are enforced by 'max_align' which is used to align the
+ tcb_offset. */
+ _dl_extra_tls_set_offset (tls_blocks_size - extra_tls_size - TLS_TP_OFFSET);
+
+ tlsblock = _dl_early_allocate (tls_blocks_size + max_align
+ TLS_PRE_TCB_SIZE
+ GLRO(dl_tls_static_surplus));
if (tlsblock == NULL)
@@ -209,11 +279,5 @@ __libc_setup_tls (void)
/* static_slotinfo.slotinfo[1].gen = 0; -- Already zero. */
static_slotinfo.slotinfo[1].map = main_map;
- memsz = roundup (memsz, align ?: 1);
-
-#if TLS_DTV_AT_TP
- memsz += tcb_offset;
-#endif
-
- init_static_tls (memsz, MAX (TCB_ALIGNMENT, max_align));
+ init_static_tls (tls_blocks_size, MAX (TCB_ALIGNMENT, max_align));
}
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index c2d17265fb..45ea0588c3 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -36,6 +36,8 @@
#define TUNABLE_NAMESPACE rtld
#include <dl-tunables.h>
+#include <dl-extra_tls.h>
+
/* Surplus static TLS, GLRO(dl_tls_static_surplus), is used for
- IE TLS in libc.so for all dlmopen namespaces except in the initial
@@ -323,6 +325,39 @@ _dl_determine_tlsoffset (void)
slotinfo[cnt].map->l_tls_offset = off;
}
+ /* Insert the extra TLS block after the last TLS block. */
+
+ /* Extra TLS block for internal usage to append at the end of the TLS blocks
+ (in allocation order). The address at which the block is allocated must
+ be aligned to 'extra_tls_align'. The size of the block as returned by
+ '_dl_extra_tls_get_size ()' is always a multiple of the aligment.
+
+ On Linux systems this is where the rseq area will be allocated. On other
+ systems it is currently unused and both values will be '0'. */
+ size_t extra_tls_size = _dl_extra_tls_get_size ();
+ size_t extra_tls_align = _dl_extra_tls_get_align ();
+
+ /* Increase the maximum alignment with the extra TLS alignment requirements
+ if necessary. */
+ max_align = MAX (max_align, extra_tls_align);
+
+ /* Add the extra TLS block to the global offset. To ensure proper alignment,
+ first align the current global offset to the extra TLS block requirements
+ and then add the extra TLS block size. Both values respect the extra TLS
+ alignment requirements and so does the resulting offset. */
+ offset = roundup (offset, extra_tls_align ?: 1) + extra_tls_size;
+
+ /* Record the extra TLS offset.
+
+ With TLS_TCB_AT_TP the TLS blocks are allocated before the thread pointer
+ in reverse order. Our block is added last which results in it being the
+ first in the static TLS block, thus record the most negative offset.
+
+ The alignment requirements of the pointer resulting from this offset and
+ the thread pointer are enforced by 'max_align' which is used to align the
+ tcb_offset. */
+ _dl_extra_tls_set_offset (-offset);
+
GL(dl_tls_static_used) = offset;
GLRO (dl_tls_static_size) = (roundup (offset + GLRO(dl_tls_static_surplus),
max_align)
@@ -368,6 +403,43 @@ _dl_determine_tlsoffset (void)
offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte;
}
+ /* Insert the extra TLS block after the last TLS block. */
+
+ /* Extra TLS block for internal usage to append at the end of the TLS blocks
+ (in allocation order). The address at which the block is allocated must
+ be aligned to 'extra_tls_align'. The size of the block as returned by
+ '_dl_extra_tls_get_size ()' is always a multiple of the aligment.
+
+ On Linux systems this is where the rseq area will be allocated. On other
+ systems it is currently unused and both values will be '0'. */
+ size_t extra_tls_size = _dl_extra_tls_get_size ();
+ size_t extra_tls_align = _dl_extra_tls_get_align ();
+
+ /* Increase the maximum alignment with the extra TLS alignment requirements
+ if necessary. */
+ max_align = MAX (max_align, extra_tls_align);
+
+ /* Align the global offset to the beginning of the extra TLS block. */
+ offset = roundup (offset, extra_tls_align ?: 1);
+
+ /* Record the extra TLS offset.
+
+ With TLS_DTV_AT_TP the TLS blocks are allocated after the thread pointer in
+ order. Our block is added last which results in it being the last in the
+ static TLS block, thus record the offset as the size of the static TLS
+ block minus the size of our block.
+
+ On some architectures the TLS blocks are offset from the thread pointer,
+ include this offset in the extra TLS block offset.
+
+ The alignment requirements of the pointer resulting from this offset and
+ the thread pointer are enforced by 'max_align' which is used to align the
+ tcb_offset. */
+ _dl_extra_tls_set_offset (offset - TLS_TP_OFFSET);
+
+ /* Add the extra TLS block to the global offset. */
+ offset += extra_tls_size;
+
GL(dl_tls_static_used) = offset;
GLRO (dl_tls_static_size) = roundup (offset + GLRO(dl_tls_static_surplus),
TCB_ALIGNMENT);
--git a/sysdeps/generic/dl-extra_tls.h b/sysdeps/generic/dl-extra_tls.h
new file mode 100644
index 0000000000..7f5b10d3e8
--- /dev/null
+++ b/sysdeps/generic/dl-extra_tls.h
@@ -0,0 +1,46 @@
+/* extra tls utils for the dynamic linker. Generic stub version.
+ Copyright (C) 2025 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DL_EXTRA_TLS_H
+#define _DL_EXTRA_TLS_H 1
+#include <stddef.h>
+
+/* In this generic version, the extra TLS block is unused. */
+
+/* Returns the size of the extra TLS block, it must always be a multiple of the
+ alignment. */
+static inline size_t
+_dl_extra_tls_get_size (void)
+{
+ return 0;
+}
+
+/* Returns the alignment requirements of the extra TLS block. */
+static inline size_t
+_dl_extra_tls_get_align (void)
+{
+ return 0;
+}
+
+/* Record the offset of the extra TLS block from the thread pointer. */
+static inline void
+_dl_extra_tls_set_offset (ptrdiff_t tls_offset __attribute__ ((unused)))
+{
+}
+
+#endif
--
2.39.5
next prev parent reply other threads:[~2025-01-09 16:32 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-09 16:32 [PATCH v16 0/8] Add rseq extensible ABI support Michael Jeanson
2025-01-09 16:32 ` [PATCH v16 1/8] nptl: Add rseq auxvals Michael Jeanson
2025-01-09 16:32 ` Michael Jeanson [this message]
2025-01-10 19:03 ` [PATCH v16 2/8] Add generic 'extra TLS' Florian Weimer
2025-01-10 19:22 ` Michael Jeanson
2025-01-11 14:51 ` Florian Weimer
2025-01-11 15:36 ` Mathieu Desnoyers
2025-01-11 16:42 ` Florian Weimer
2025-01-11 17:06 ` Mark Wielaard
2025-01-11 19:11 ` Andreas K. Huettel
2025-01-12 10:05 ` Florian Weimer
2025-01-09 16:32 ` [PATCH v16 3/8] Add Linux " Michael Jeanson
2025-01-09 16:32 ` [PATCH v16 4/8] nptl: add rtld_hidden_proto to __rseq_size and __rseq_offset Michael Jeanson
2025-01-10 19:05 ` Florian Weimer
2025-01-10 19:26 ` Michael Jeanson
2025-01-09 16:32 ` [PATCH v16 5/8] nptl: Introduce <rseq-access.h> for RSEQ_* accessors Michael Jeanson
2025-01-10 19:08 ` Florian Weimer
2025-01-13 10:49 ` Frank Scheiner
2025-01-13 19:11 ` Michael Jeanson
2025-01-14 20:49 ` Frank Scheiner
2025-01-09 16:32 ` [PATCH v16 6/8] nptl: Move the rseq area to the 'extra TLS' block Michael Jeanson
2025-01-10 19:39 ` Florian Weimer
2025-01-16 13:24 ` Stefan Liebler
2025-01-16 15:45 ` Michael Jeanson
2025-01-16 16:26 ` Stefan Liebler
2025-01-16 16:43 ` Michael Jeanson
2025-01-16 17:04 ` Michael Jeanson
2025-01-16 21:28 ` Michael Jeanson
2025-01-17 12:43 ` Stefan Liebler
2025-01-11 2:53 ` H.J. Lu
2025-01-09 16:32 ` [PATCH v16 7/8] nptl: Remove the rseq area from 'struct pthread' Michael Jeanson
2025-01-09 16:32 ` [PATCH v16 8/8] Linux: Update internal copy of '<sys/rseq.h>' Michael Jeanson
2025-01-10 15:39 ` [PATCH v16 0/8] Add rseq extensible ABI support Michael Jeanson
2025-01-10 16:32 ` Adhemerval Zanella Netto
2025-01-10 18:08 ` Florian Weimer
2025-01-10 19:17 ` Michael Jeanson
2025-01-10 19:40 ` Florian Weimer
2025-01-10 19:51 ` Michael Jeanson
2025-01-10 19:58 ` Florian Weimer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250109163215.2343659-3-mjeanson@efficios.com \
--to=mjeanson@efficios.com \
--cc=carlos@redhat.com \
--cc=dj@redhat.com \
--cc=fweimer@redhat.com \
--cc=libc-alpha@sourceware.org \
--cc=mathieu.desnoyers@efficios.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).