| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- /* Initialization code for TLS in statically linked application.
- Copyright (C) 2002-2026 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/>. */
- #include <startup.h>
- #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>
- #include <array_length.h>
- #include <elf/dl-tls_block_align.h>
- #include <dl-symbol-redir-ifunc.h>
- #ifdef SHARED
- #error makefile bug, this file is for static only
- #endif
- dtv_t _dl_static_dtv[2 + TLS_SLOTINFO_SURPLUS];
- static struct dtv_slotinfo_list static_slotinfo =
- {
- /* Allocate an array of 2 + TLS_SLOTINFO_SURPLUS elements. */
- .slotinfo = { [array_length (_dl_static_dtv) - 1] = { 0 } },
- };
- /* Highest dtv index currently needed. */
- size_t _dl_tls_max_dtv_idx;
- /* Flag signalling whether there are gaps in the module ID allocation. */
- bool _dl_tls_dtv_gaps;
- /* Information about the dtv slots. */
- struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list;
- /* Number of modules in the static TLS block. */
- size_t _dl_tls_static_nelem;
- /* Size of the static TLS block. */
- size_t _dl_tls_static_size;
- /* Size actually allocated in the static TLS block. */
- size_t _dl_tls_static_used;
- /* Alignment requirement of the static TLS block. */
- size_t _dl_tls_static_align;
- /* Size of surplus space in the static TLS area for dynamically
- loaded modules with IE-model TLS or for TLSDESC optimization.
- See comments in elf/dl-tls.c where it is initialized. */
- size_t _dl_tls_static_surplus;
- /* Remaining amount of static TLS that may be used for optimizing
- dynamic TLS access (e.g. with TLSDESC). */
- size_t _dl_tls_static_optional;
- /* Generation counter for the dtv. */
- size_t _dl_tls_generation;
- /* Additional definitions needed by TLS initialization. */
- #ifdef TLS_INIT_HELPER
- TLS_INIT_HELPER
- #endif
- static void
- init_slotinfo (struct link_map *main_map)
- {
- /* Create the slotinfo list. Note that the type of static_slotinfo
- has effectively a zero-length array, so we cannot use the size of
- static_slotinfo to determine the array length. */
- static_slotinfo.len = array_length (_dl_static_dtv);
- /* static_slotinfo.next = NULL; -- Already zero. */
- main_map->l_tls_modid = 1;
- static_slotinfo.slotinfo[1].map = main_map;
- main_map->l_tls_in_slotinfo = 1;
- /* The slotinfo list. Will be extended by the code doing dynamic
- linking. */
- GL(dl_tls_max_dtv_idx) = 1;
- GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo;
- }
- /* Perform TLS setup for statically linked binaries. Similar to
- init_tls in elf/rtld.c. */
- void
- __libc_setup_tls (void)
- {
- size_t memsz = 0;
- size_t filesz = 0;
- void *initimage = NULL;
- size_t align = 0;
- size_t max_align = TCB_ALIGNMENT;
- const ElfW(Phdr) *phdr;
- struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
- __tls_pre_init_tp ();
- /* Look through the TLS segment if there is any. */
- for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
- if (phdr->p_type == PT_TLS)
- {
- /* Remember the values we need. */
- memsz = phdr->p_memsz;
- filesz = phdr->p_filesz;
- initimage = (void *) phdr->p_vaddr + main_map->l_addr;
- align = phdr->p_align;
- if (phdr->p_align > max_align)
- max_align = phdr->p_align;
- main_map->l_tls_align = align;
- main_map->l_tls_blocksize = memsz;
- main_map->l_tls_initimage = initimage;
- main_map->l_tls_initimage_size = filesz;
- init_slotinfo (main_map);
- break;
- }
- /* Number of elements in the static TLS block. */
- GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
- /* Calculate the size of the static TLS surplus, with 0 auditors. */
- _dl_tls_static_surplus_init (0);
- /* Calculate the TLS block size. */
- _dl_determine_tlsoffset ();
- /* See _dl_allocate_tls_storage in elf/dl-tls.c. */
- void *tcbp;
- {
- size_t size = _dl_tls_block_size_with_pre ();
- void *allocated = _dl_early_allocate (size + GLRO (dl_tls_static_align));
- if (allocated == NULL)
- _startup_fatal_tls_error ();
- tcbp = _dl_tls_block_align (size, allocated);
- }
- /* Initialize the dtv. [0] is the length, [1] the generation counter. */
- _dl_static_dtv[0].counter = array_length (_dl_static_dtv) - 2;
- /* Install the pointer to the DTV. See allocate_dtv in elf/dl-tls.c. */
- INSTALL_DTV (tcbp, _dl_static_dtv);
- /* _dl_allocate_tls_init uses recursive locking and the TCB, so this
- has to come first. */
- call_tls_init_tp (tcbp);
- /* Initialize the TLS image for the allocated TCB. */
- _dl_allocate_tls_init (tcbp, true);
- }
|