Overwrite target for x86_64_v2

This commit is contained in:
Eduard Abdullin 2025-08-22 01:40:28 +00:00 committed by root
commit 6ac62bdd5e
43 changed files with 8791 additions and 3 deletions

View File

@ -0,0 +1,27 @@
commit b6ea8902a72fb746ae5cd71ddf1172c5ead89972
Author: Wilco Dijkstra <wilco.dijkstra@arm.com>
Date: Fri Jun 27 14:10:55 2025 +0000
AArch64: Avoid memset ifunc in cpu-features.c [BZ #33112]
During early startup memcpy or memset must not be called since many targets
use ifuncs for them which won't be initialized yet. Security hardening may
use -ftrivial-auto-var-init=zero which inserts calls to memset. Redirect
memset to memset_generic by including dl-symbol-redir-ifunc.h in cpu-features.c.
This fixes BZ #33112.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 681a24ae4d0cb8ed92de98b4da660308840b09ba)
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index c0b047bc0dbeae42..0ad55a0c7f66618f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -23,6 +23,7 @@
#include <sys/prctl.h>
#include <sys/utsname.h>
#include <dl-tunables-parse.h>
+#include <dl-symbol-redir-ifunc.h>
#define DCZID_DZP_MASK (1 << 4)
#define DCZID_BS_MASK (0xf)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,135 @@
commit 392e6cf1e86e29fe155c21351cd7b7a0fd371f5b
Author: Luna Lamb <luna.lamb@arm.com>
Date: Thu May 29 15:22:51 2025 +0000
AArch64: Improve codegen in SVE log1p
Improves memory access, reformat evaluation scheme to pack coefficients.
5% improvement in throughput microbenchmark on Neoverse V1.
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
(cherry picked from commit da196e6134ede64728006518352d75b6c3902fec)
diff --git a/sysdeps/aarch64/fpu/log1p_sve.c b/sysdeps/aarch64/fpu/log1p_sve.c
index 04f7e5720e13c371..5251f3c07566eec3 100644
--- a/sysdeps/aarch64/fpu/log1p_sve.c
+++ b/sysdeps/aarch64/fpu/log1p_sve.c
@@ -22,19 +22,33 @@
static const struct data
{
- double poly[19];
+ float64_t c0, c2, c4, c6, c8, c10, c12, c14, c16;
+ float64_t c1, c3, c5, c7, c9, c11, c13, c15, c17, c18;
double ln2_hi, ln2_lo;
uint64_t hfrt2_top, onemhfrt2_top, inf, mone;
} data = {
/* Generated using Remez in [ sqrt(2)/2 - 1, sqrt(2) - 1]. Order 20
- polynomial, however first 2 coefficients are 0 and 1 so are not stored. */
- .poly = { -0x1.ffffffffffffbp-2, 0x1.55555555551a9p-2, -0x1.00000000008e3p-2,
- 0x1.9999999a32797p-3, -0x1.555555552fecfp-3, 0x1.249248e071e5ap-3,
- -0x1.ffffff8bf8482p-4, 0x1.c71c8f07da57ap-4, -0x1.9999ca4ccb617p-4,
- 0x1.7459ad2e1dfa3p-4, -0x1.554d2680a3ff2p-4, 0x1.3b4c54d487455p-4,
- -0x1.2548a9ffe80e6p-4, 0x1.0f389a24b2e07p-4, -0x1.eee4db15db335p-5,
- 0x1.e95b494d4a5ddp-5, -0x1.15fdf07cb7c73p-4, 0x1.0310b70800fcfp-4,
- -0x1.cfa7385bdb37ep-6, },
+ polynomial, however first 2 coefficients are 0 and 1 so are not
+ stored. */
+ .c0 = -0x1.ffffffffffffbp-2,
+ .c1 = 0x1.55555555551a9p-2,
+ .c2 = -0x1.00000000008e3p-2,
+ .c3 = 0x1.9999999a32797p-3,
+ .c4 = -0x1.555555552fecfp-3,
+ .c5 = 0x1.249248e071e5ap-3,
+ .c6 = -0x1.ffffff8bf8482p-4,
+ .c7 = 0x1.c71c8f07da57ap-4,
+ .c8 = -0x1.9999ca4ccb617p-4,
+ .c9 = 0x1.7459ad2e1dfa3p-4,
+ .c10 = -0x1.554d2680a3ff2p-4,
+ .c11 = 0x1.3b4c54d487455p-4,
+ .c12 = -0x1.2548a9ffe80e6p-4,
+ .c13 = 0x1.0f389a24b2e07p-4,
+ .c14 = -0x1.eee4db15db335p-5,
+ .c15 = 0x1.e95b494d4a5ddp-5,
+ .c16 = -0x1.15fdf07cb7c73p-4,
+ .c17 = 0x1.0310b70800fcfp-4,
+ .c18 = -0x1.cfa7385bdb37ep-6,
.ln2_hi = 0x1.62e42fefa3800p-1,
.ln2_lo = 0x1.ef35793c76730p-45,
/* top32(asuint64(sqrt(2)/2)) << 32. */
@@ -49,7 +63,7 @@ static const struct data
#define BottomMask 0xffffffff
static svfloat64_t NOINLINE
-special_case (svbool_t special, svfloat64_t x, svfloat64_t y)
+special_case (svfloat64_t x, svfloat64_t y, svbool_t special)
{
return sv_call_f64 (log1p, x, y, special);
}
@@ -91,8 +105,9 @@ svfloat64_t SV_NAME_D1 (log1p) (svfloat64_t x, svbool_t pg)
/* Reduce x to f in [sqrt(2)/2, sqrt(2)]. */
svuint64_t utop
= svadd_x (pg, svand_x (pg, u, 0x000fffff00000000), d->hfrt2_top);
- svuint64_t u_red = svorr_x (pg, utop, svand_x (pg, mi, BottomMask));
- svfloat64_t f = svsub_x (pg, svreinterpret_f64 (u_red), 1);
+ svuint64_t u_red
+ = svorr_x (pg, utop, svand_x (svptrue_b64 (), mi, BottomMask));
+ svfloat64_t f = svsub_x (svptrue_b64 (), svreinterpret_f64 (u_red), 1);
/* Correction term c/m. */
svfloat64_t cm = svdiv_x (pg, svsub_x (pg, x, svsub_x (pg, m, 1)), m);
@@ -103,16 +118,47 @@ svfloat64_t SV_NAME_D1 (log1p) (svfloat64_t x, svbool_t pg)
Hence approximation has the form f + f^2 * P(f)
where P(x) = C0 + C1*x + C2x^2 + ...
Assembling this all correctly is dealt with at the final step. */
- svfloat64_t f2 = svmul_x (pg, f, f), f4 = svmul_x (pg, f2, f2),
- f8 = svmul_x (pg, f4, f4), f16 = svmul_x (pg, f8, f8);
- svfloat64_t p = sv_estrin_18_f64_x (pg, f, f2, f4, f8, f16, d->poly);
+ svfloat64_t f2 = svmul_x (svptrue_b64 (), f, f),
+ f4 = svmul_x (svptrue_b64 (), f2, f2),
+ f8 = svmul_x (svptrue_b64 (), f4, f4),
+ f16 = svmul_x (svptrue_b64 (), f8, f8);
+
+ svfloat64_t c13 = svld1rq (svptrue_b64 (), &d->c1);
+ svfloat64_t c57 = svld1rq (svptrue_b64 (), &d->c5);
+ svfloat64_t c911 = svld1rq (svptrue_b64 (), &d->c9);
+ svfloat64_t c1315 = svld1rq (svptrue_b64 (), &d->c13);
+ svfloat64_t c1718 = svld1rq (svptrue_b64 (), &d->c17);
+
+ /* Order-18 Estrin scheme. */
+ svfloat64_t p01 = svmla_lane (sv_f64 (d->c0), f, c13, 0);
+ svfloat64_t p23 = svmla_lane (sv_f64 (d->c2), f, c13, 1);
+ svfloat64_t p45 = svmla_lane (sv_f64 (d->c4), f, c57, 0);
+ svfloat64_t p67 = svmla_lane (sv_f64 (d->c6), f, c57, 1);
+
+ svfloat64_t p03 = svmla_x (pg, p01, f2, p23);
+ svfloat64_t p47 = svmla_x (pg, p45, f2, p67);
+ svfloat64_t p07 = svmla_x (pg, p03, f4, p47);
+
+ svfloat64_t p89 = svmla_lane (sv_f64 (d->c8), f, c911, 0);
+ svfloat64_t p1011 = svmla_lane (sv_f64 (d->c10), f, c911, 1);
+ svfloat64_t p1213 = svmla_lane (sv_f64 (d->c12), f, c1315, 0);
+ svfloat64_t p1415 = svmla_lane (sv_f64 (d->c14), f, c1315, 1);
+
+ svfloat64_t p811 = svmla_x (pg, p89, f2, p1011);
+ svfloat64_t p1215 = svmla_x (pg, p1213, f2, p1415);
+ svfloat64_t p815 = svmla_x (pg, p811, f4, p1215);
+
+ svfloat64_t p015 = svmla_x (pg, p07, f8, p815);
+ svfloat64_t p1617 = svmla_lane (sv_f64 (d->c16), f, c1718, 0);
+ svfloat64_t p1618 = svmla_lane (p1617, f2, c1718, 1);
+ svfloat64_t p = svmla_x (pg, p015, f16, p1618);
svfloat64_t ylo = svmla_x (pg, cm, k, d->ln2_lo);
svfloat64_t yhi = svmla_x (pg, f, k, d->ln2_hi);
- svfloat64_t y = svmla_x (pg, svadd_x (pg, ylo, yhi), f2, p);
if (__glibc_unlikely (svptest_any (pg, special)))
- return special_case (special, x, y);
-
- return y;
+ return special_case (
+ x, svmla_x (svptrue_b64 (), svadd_x (svptrue_b64 (), ylo, yhi), f2, p),
+ special);
+ return svmla_x (svptrue_b64 (), svadd_x (svptrue_b64 (), ylo, yhi), f2, p);
}

View File

@ -0,0 +1,193 @@
commit fbade65338cff0a3a1699a8627a8180e9a01a627
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Feb 22 10:42:55 2024 -0300
arm: Use _dl_find_object on __gnu_Unwind_Find_exidx (BZ 31405)
Instead of __dl_iterate_phdr. On ARM dlfo_eh_frame/dlfo_eh_count
maps to PT_ARM_EXIDX vaddr start / length.
On a Neoverse N1 machine with 160 cores, the following program:
$ cat test.c
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
enum {
niter = 1024,
ntimes = 128,
};
static void *
tf (void *arg)
{
int a = (int) arg;
for (int i = 0; i < niter; i++)
{
void *p[ntimes];
for (int j = 0; j < ntimes; j++)
p[j] = malloc (a * 128);
for (int j = 0; j < ntimes; j++)
free (p[j]);
}
return NULL;
}
int main (int argc, char *argv[])
{
enum { nthreads = 16 };
pthread_t t[nthreads];
for (int i = 0; i < nthreads; i ++)
assert (pthread_create (&t[i], NULL, tf, (void *) i) == 0);
for (int i = 0; i < nthreads; i++)
{
void *r;
assert (pthread_join (t[i], &r) == 0);
assert (r == NULL);
}
return 0;
}
$ arm-linux-gnueabihf-gcc -fsanitize=address test.c -o test
Improves from ~15s to 0.5s.
Checked on arm-linux-gnueabihf.
(cherry picked from commit f4c142bb9fe6b02c0af8cfca8a920091e2dba44b)
diff --git a/elf/Makefile b/elf/Makefile
index 92da608da1ebc175..f5646c434f19a667 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -34,6 +34,7 @@ routines = \
dl-addr \
dl-addr-obj \
dl-early_allocate \
+ dl-find_object \
dl-iteratephdr \
dl-libc \
dl-origin \
@@ -60,7 +61,6 @@ dl-routines = \
dl-deps \
dl-exception \
dl-execstack \
- dl-find_object \
dl-fini \
dl-init \
dl-load \
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 940fa5c2236af666..449302eda35ce96f 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -356,7 +356,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
}
int
-_dl_find_object (void *pc1, struct dl_find_object *result)
+__dl_find_object (void *pc1, struct dl_find_object *result)
{
uintptr_t pc = (uintptr_t) pc1;
@@ -463,7 +463,8 @@ _dl_find_object (void *pc1, struct dl_find_object *result)
return -1;
} /* Transaction retry loop. */
}
-rtld_hidden_def (_dl_find_object)
+hidden_def (__dl_find_object)
+weak_alias (__dl_find_object, _dl_find_object)
/* _dlfo_process_initial is called twice. First to compute the array
sizes from the initial loaded mappings. Second to fill in the
diff --git a/include/dlfcn.h b/include/dlfcn.h
index a44420fa37439a85..f49ee1b0c9958d38 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -4,7 +4,8 @@
#include <link.h> /* For ElfW. */
#include <stdbool.h>
-rtld_hidden_proto (_dl_find_object)
+extern __typeof (_dl_find_object) __dl_find_object;
+hidden_proto (__dl_find_object)
/* Internally used flag. */
#define __RTLD_DLOPEN 0x80000000
diff --git a/sysdeps/arm/find_exidx.c b/sysdeps/arm/find_exidx.c
index d647865e5a098cd5..a924d59b9f75d7b2 100644
--- a/sysdeps/arm/find_exidx.c
+++ b/sysdeps/arm/find_exidx.c
@@ -16,64 +16,15 @@
<https://www.gnu.org/licenses/>. */
#include <link.h>
-#include <unwind.h>
-
-struct unw_eh_callback_data
-{
- _Unwind_Ptr pc;
- _Unwind_Ptr exidx_start;
- int exidx_len;
-};
-
-
-/* Callback to determines if the PC lies within an object, and remember the
- location of the exception index table if it does. */
-
-static int
-find_exidx_callback (struct dl_phdr_info * info, size_t size, void * ptr)
-{
- struct unw_eh_callback_data * data;
- const ElfW(Phdr) *phdr;
- int i;
- int match;
- _Unwind_Ptr load_base;
-
- data = (struct unw_eh_callback_data *) ptr;
- load_base = info->dlpi_addr;
- phdr = info->dlpi_phdr;
-
- match = 0;
- for (i = info->dlpi_phnum; i > 0; i--, phdr++)
- {
- if (phdr->p_type == PT_LOAD)
- {
- _Unwind_Ptr vaddr = phdr->p_vaddr + load_base;
- if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
- match = 1;
- }
- else if (phdr->p_type == PT_ARM_EXIDX)
- {
- data->exidx_start = (_Unwind_Ptr) (phdr->p_vaddr + load_base);
- data->exidx_len = phdr->p_memsz;
- }
- }
-
- return match;
-}
-
/* Find the exception index table containing PC. */
_Unwind_Ptr
__gnu_Unwind_Find_exidx (_Unwind_Ptr pc, int * pcount)
{
- struct unw_eh_callback_data data;
-
- data.pc = pc;
- data.exidx_start = 0;
- if (__dl_iterate_phdr (find_exidx_callback, &data) <= 0)
+ struct dl_find_object data;
+ if (__dl_find_object ((void *) pc, &data) < 0)
return 0;
-
- *pcount = data.exidx_len / 8;
- return data.exidx_start;
+ *pcount = data.dlfo_eh_count;
+ return (_Unwind_Ptr) data.dlfo_eh_frame;
}

View File

@ -0,0 +1,93 @@
commit 9833fcf7ce7a7ac7ec5b7694fd4c2bc705282842
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Feb 1 12:37:58 2025 +0100
elf: Do not add a copy of _dl_find_object to libc.so
This reduces code size and dependencies on ld.so internals from
libc.so.
Fixes commit f4c142bb9fe6b02c0af8cfca8a920091e2dba44b
("arm: Use _dl_find_object on __gnu_Unwind_Find_exidx (BZ 31405)").
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 96429bcc91a14f71b177ddc5e716de3069060f2c)
diff --git a/elf/Makefile b/elf/Makefile
index f5646c434f19a667..92da608da1ebc175 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -34,7 +34,6 @@ routines = \
dl-addr \
dl-addr-obj \
dl-early_allocate \
- dl-find_object \
dl-iteratephdr \
dl-libc \
dl-origin \
@@ -61,6 +60,7 @@ dl-routines = \
dl-deps \
dl-exception \
dl-execstack \
+ dl-find_object \
dl-fini \
dl-init \
dl-load \
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 449302eda35ce96f..940fa5c2236af666 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -356,7 +356,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
}
int
-__dl_find_object (void *pc1, struct dl_find_object *result)
+_dl_find_object (void *pc1, struct dl_find_object *result)
{
uintptr_t pc = (uintptr_t) pc1;
@@ -463,8 +463,7 @@ __dl_find_object (void *pc1, struct dl_find_object *result)
return -1;
} /* Transaction retry loop. */
}
-hidden_def (__dl_find_object)
-weak_alias (__dl_find_object, _dl_find_object)
+rtld_hidden_def (_dl_find_object)
/* _dlfo_process_initial is called twice. First to compute the array
sizes from the initial loaded mappings. Second to fill in the
diff --git a/include/dlfcn.h b/include/dlfcn.h
index f49ee1b0c9958d38..a44420fa37439a85 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -4,8 +4,7 @@
#include <link.h> /* For ElfW. */
#include <stdbool.h>
-extern __typeof (_dl_find_object) __dl_find_object;
-hidden_proto (__dl_find_object)
+rtld_hidden_proto (_dl_find_object)
/* Internally used flag. */
#define __RTLD_DLOPEN 0x80000000
diff --git a/sysdeps/arm/find_exidx.c b/sysdeps/arm/find_exidx.c
index a924d59b9f75d7b2..4257c268381df540 100644
--- a/sysdeps/arm/find_exidx.c
+++ b/sysdeps/arm/find_exidx.c
@@ -15,6 +15,7 @@
License along with the GNU C Library. If not, see
<https://www.gnu.org/licenses/>. */
+#include <ldsodefs.h>
#include <link.h>
/* Find the exception index table containing PC. */
@@ -23,7 +24,7 @@ _Unwind_Ptr
__gnu_Unwind_Find_exidx (_Unwind_Ptr pc, int * pcount)
{
struct dl_find_object data;
- if (__dl_find_object ((void *) pc, &data) < 0)
+ if (GLRO(dl_find_object) ((void *) pc, &data) < 0)
return 0;
*pcount = data.dlfo_eh_count;
return (_Unwind_Ptr) data.dlfo_eh_frame;

View File

@ -0,0 +1,89 @@
commit 64488b4b31d63b59b06b42ad93a092053364801b
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 1 10:20:23 2025 +0200
elf: Extract rtld_setup_phdr function from dl_main
Remove historic binutils reference from comment and update
how this data is used by applications.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 2cac9559e06044ba520e785c151fbbd25011865f)
diff --git a/elf/rtld.c b/elf/rtld.c
index 3ca9a11009a74626..3bf9707e0007bc83 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1284,6 +1284,37 @@ rtld_setup_main_map (struct link_map *main_map)
return has_interp;
}
+/* Set up the program header information for the dynamic linker
+ itself. It can be accessed via _r_debug and dl_iterate_phdr
+ callbacks. */
+static void
+rtld_setup_phdr (void)
+{
+ /* Starting from binutils-2.23, the linker will define the magic
+ symbol __ehdr_start to point to our own ELF header if it is
+ visible in a segment that also includes the phdrs. */
+
+ const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
+ assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
+ assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
+
+ const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
+
+ GL(dl_rtld_map).l_phdr = rtld_phdr;
+ GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
+
+
+ /* PT_GNU_RELRO is usually the last phdr. */
+ size_t cnt = rtld_ehdr->e_phnum;
+ while (cnt-- > 0)
+ if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
+ {
+ GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
+ GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
+ break;
+ }
+}
+
/* Adjusts the contents of the stack and related globals for the user
entry point. The ld.so processed skip_args arguments and bumped
_dl_argv and _dl_argc accordingly. Those arguments are removed from
@@ -1749,33 +1780,7 @@ dl_main (const ElfW(Phdr) *phdr,
++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
++GL(dl_load_adds);
- /* Starting from binutils-2.23, the linker will define the magic symbol
- __ehdr_start to point to our own ELF header if it is visible in a
- segment that also includes the phdrs. If that's not available, we use
- the old method that assumes the beginning of the file is part of the
- lowest-addressed PT_LOAD segment. */
-
- /* Set up the program header information for the dynamic linker
- itself. It is needed in the dl_iterate_phdr callbacks. */
- const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
- assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
- assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
-
- const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
-
- GL(dl_rtld_map).l_phdr = rtld_phdr;
- GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
-
-
- /* PT_GNU_RELRO is usually the last phdr. */
- size_t cnt = rtld_ehdr->e_phnum;
- while (cnt-- > 0)
- if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
- {
- GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
- GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
- break;
- }
+ rtld_setup_phdr ();
/* Add the dynamic linker to the TLS list if it also uses TLS. */
if (GL(dl_rtld_map).l_tls_blocksize != 0)

View File

@ -0,0 +1,448 @@
commit 49f0e73fa3279465f4c9d86a286c3812cc377061
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 1 12:19:49 2025 +0200
elf: Handle ld.so with LOAD segment gaps in _dl_find_object (bug 31943)
Detect if ld.so not contiguous and handle that case in _dl_find_object.
Set l_find_object_processed even for initially loaded link maps,
otherwise dlopen of an initially loaded object adds it to
_dlfo_loaded_mappings (where maps are expected to be contiguous),
in addition to _dlfo_nodelete_mappings.
Test elf/tst-link-map-contiguous-ldso iterates over the loader
image, reading every word to make sure memory is actually mapped.
It only does that if the l_contiguous flag is set for the link map.
Otherwise, it finds gaps with mmap and checks that _dl_find_object
does not return the ld.so mapping for them.
The test elf/tst-link-map-contiguous-main does the same thing for
the libc.so shared object. This only works if the kernel loaded
the main program because the glibc dynamic loader may fill
the gaps with PROT_NONE mappings in some cases, making it contiguous,
but accesses to individual words may still fault.
Test elf/tst-link-map-contiguous-libc is again slightly different
because the dynamic loader always fills the gaps with PROT_NONE
mappings, so a different form of probing has to be used.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 20681be149b9eb1b6c1f4246bf4bd801221c86cd)
diff --git a/elf/Makefile b/elf/Makefile
index 92da608da1ebc175..3085a0844c6604fe 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -514,6 +514,8 @@ tests-internal += \
tst-dl_find_object \
tst-dl_find_object-threads \
tst-dlmopen2 \
+ tst-link-map-contiguous-ldso \
+ tst-link-map-contiguous-libc \
tst-ptrguard1 \
tst-stackguard1 \
tst-tls-surplus \
@@ -525,6 +527,10 @@ tests-internal += \
unload2 \
# tests-internal
+ifeq ($(build-hardcoded-path-in-tests),yes)
+tests-internal += tst-link-map-contiguous-main
+endif
+
tests-container += \
tst-dlopen-self-container \
tst-dlopen-tlsmodid-container \
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 940fa5c2236af666..0e45f0af32c9e6b4 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -465,6 +465,37 @@ _dl_find_object (void *pc1, struct dl_find_object *result)
}
rtld_hidden_def (_dl_find_object)
+/* Subroutine of _dlfo_process_initial to split out noncontigous link
+ maps. NODELETE is the number of used _dlfo_nodelete_mappings
+ elements. It is incremented as needed, and the new NODELETE value
+ is returned. */
+static size_t
+_dlfo_process_initial_noncontiguous_map (struct link_map *map,
+ size_t nodelete)
+{
+ struct dl_find_object_internal dlfo;
+ _dl_find_object_from_map (map, &dlfo);
+
+ /* PT_LOAD segments for a non-contiguous link map are added to the
+ non-closeable mappings. */
+ const ElfW(Phdr) *ph = map->l_phdr;
+ const ElfW(Phdr) *ph_end = map->l_phdr + map->l_phnum;
+ for (; ph < ph_end; ++ph)
+ if (ph->p_type == PT_LOAD)
+ {
+ if (_dlfo_nodelete_mappings != NULL)
+ {
+ /* Second pass only. */
+ _dlfo_nodelete_mappings[nodelete] = dlfo;
+ ElfW(Addr) start = ph->p_vaddr + map->l_addr;
+ _dlfo_nodelete_mappings[nodelete].map_start = start;
+ _dlfo_nodelete_mappings[nodelete].map_end = start + ph->p_memsz;
+ }
+ ++nodelete;
+ }
+ return nodelete;
+}
+
/* _dlfo_process_initial is called twice. First to compute the array
sizes from the initial loaded mappings. Second to fill in the
bases and infos arrays with the (still unsorted) data. Returns the
@@ -476,29 +507,8 @@ _dlfo_process_initial (void)
size_t nodelete = 0;
if (!main_map->l_contiguous)
- {
- struct dl_find_object_internal dlfo;
- _dl_find_object_from_map (main_map, &dlfo);
-
- /* PT_LOAD segments for a non-contiguous are added to the
- non-closeable mappings. */
- for (const ElfW(Phdr) *ph = main_map->l_phdr,
- *ph_end = main_map->l_phdr + main_map->l_phnum;
- ph < ph_end; ++ph)
- if (ph->p_type == PT_LOAD)
- {
- if (_dlfo_nodelete_mappings != NULL)
- {
- /* Second pass only. */
- _dlfo_nodelete_mappings[nodelete] = dlfo;
- _dlfo_nodelete_mappings[nodelete].map_start
- = ph->p_vaddr + main_map->l_addr;
- _dlfo_nodelete_mappings[nodelete].map_end
- = _dlfo_nodelete_mappings[nodelete].map_start + ph->p_memsz;
- }
- ++nodelete;
- }
- }
+ /* Contiguous case already handled in _dl_find_object_init. */
+ nodelete = _dlfo_process_initial_noncontiguous_map (main_map, nodelete);
size_t loaded = 0;
for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
@@ -510,11 +520,22 @@ _dlfo_process_initial (void)
/* lt_library link maps are implicitly NODELETE. */
if (l->l_type == lt_library || l->l_nodelete_active)
{
- if (_dlfo_nodelete_mappings != NULL)
- /* Second pass only. */
- _dl_find_object_from_map
- (l, _dlfo_nodelete_mappings + nodelete);
- ++nodelete;
+ /* The kernel may have loaded ld.so with gaps. */
+ if (!l->l_contiguous
+#ifdef SHARED
+ && l == &GL(dl_rtld_map)
+#endif
+ )
+ nodelete
+ = _dlfo_process_initial_noncontiguous_map (l, nodelete);
+ else
+ {
+ if (_dlfo_nodelete_mappings != NULL)
+ /* Second pass only. */
+ _dl_find_object_from_map
+ (l, _dlfo_nodelete_mappings + nodelete);
+ ++nodelete;
+ }
}
else if (l->l_type == lt_loaded)
{
@@ -756,7 +777,6 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
/* Prefer newly loaded link map. */
assert (loaded_index1 > 0);
_dl_find_object_from_map (loaded[loaded_index1 - 1], dlfo);
- loaded[loaded_index1 - 1]->l_find_object_processed = 1;
--loaded_index1;
}
diff --git a/elf/dl-find_object.h b/elf/dl-find_object.h
index 0915065be065504d..8894c6657c9dc309 100644
--- a/elf/dl-find_object.h
+++ b/elf/dl-find_object.h
@@ -87,7 +87,7 @@ _dl_find_object_to_external (struct dl_find_object_internal *internal,
}
/* Extract the object location data from a link map and writes it to
- *RESULT using relaxed MO stores. */
+ *RESULT using relaxed MO stores. Set L->l_find_object_processed. */
static void __attribute__ ((unused))
_dl_find_object_from_map (struct link_map *l,
struct dl_find_object_internal *result)
@@ -100,6 +100,8 @@ _dl_find_object_from_map (struct link_map *l,
atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
#endif
+ l->l_find_object_processed = 1;
+
for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
ph < ph_end; ++ph)
if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
diff --git a/elf/rtld.c b/elf/rtld.c
index 3bf9707e0007bc83..4760633866cf9159 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1286,7 +1286,7 @@ rtld_setup_main_map (struct link_map *main_map)
/* Set up the program header information for the dynamic linker
itself. It can be accessed via _r_debug and dl_iterate_phdr
- callbacks. */
+ callbacks, and it is used by _dl_find_object. */
static void
rtld_setup_phdr (void)
{
@@ -1304,6 +1304,29 @@ rtld_setup_phdr (void)
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
+ GL(dl_rtld_map).l_contiguous = 1;
+ /* The linker may not have produced a contiguous object. The kernel
+ will load the object with actual gaps (unlike the glibc loader
+ for shared objects, which always produces a contiguous mapping).
+ See similar logic in rtld_setup_main_map above. */
+ {
+ ElfW(Addr) expected_load_address = 0;
+ for (const ElfW(Phdr) *ph = rtld_phdr; ph < &rtld_phdr[rtld_ehdr->e_phnum];
+ ++ph)
+ if (ph->p_type == PT_LOAD)
+ {
+ ElfW(Addr) mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
+ if (GL(dl_rtld_map).l_contiguous && expected_load_address != 0
+ && expected_load_address != mapstart)
+ GL(dl_rtld_map).l_contiguous = 0;
+ ElfW(Addr) allocend = ph->p_vaddr + ph->p_memsz;
+ /* The next expected address is the page following this load
+ segment. */
+ expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
+ & ~(GLRO(dl_pagesize) - 1));
+ }
+ }
+
/* PT_GNU_RELRO is usually the last phdr. */
size_t cnt = rtld_ehdr->e_phnum;
while (cnt-- > 0)
diff --git a/elf/tst-link-map-contiguous-ldso.c b/elf/tst-link-map-contiguous-ldso.c
new file mode 100644
index 0000000000000000..04de808bb234fe38
--- /dev/null
+++ b/elf/tst-link-map-contiguous-ldso.c
@@ -0,0 +1,98 @@
+/* Check that _dl_find_object behavior matches up with gaps.
+ 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/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <link.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ struct link_map *l = xdlopen (LD_SO, RTLD_NOW);
+ if (!l->l_contiguous)
+ {
+ puts ("info: ld.so link map is not contiguous");
+
+ /* Try to find holes by probing with mmap. */
+ int pagesize = getpagesize ();
+ bool gap_found = false;
+ ElfW(Addr) addr = l->l_map_start;
+ TEST_COMPARE (addr % pagesize, 0);
+ while (addr < l->l_map_end)
+ {
+ void *expected = (void *) addr;
+ void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
+ struct dl_find_object dlfo;
+ int dlfo_ret = _dl_find_object (expected, &dlfo);
+ if (ptr == expected)
+ {
+ if (dlfo_ret < 0)
+ {
+ TEST_COMPARE (dlfo_ret, -1);
+ printf ("info: hole without mapping data found at %p\n", ptr);
+ }
+ else
+ FAIL ("object \"%s\" found in gap at %p",
+ dlfo.dlfo_link_map->l_name, ptr);
+ gap_found = true;
+ }
+ else if (dlfo_ret == 0)
+ {
+ if ((void *) dlfo.dlfo_link_map != (void *) l)
+ {
+ printf ("info: object \"%s\" found at %p\n",
+ dlfo.dlfo_link_map->l_name, ptr);
+ gap_found = true;
+ }
+ }
+ else
+ TEST_COMPARE (dlfo_ret, -1);
+ xmunmap (ptr, 1);
+ addr += pagesize;
+ }
+ if (!gap_found)
+ FAIL ("no ld.so gap found");
+ }
+ else
+ {
+ puts ("info: ld.so link map is contiguous");
+
+ /* Assert that ld.so is truly contiguous in memory. */
+ volatile long int *p = (volatile long int *) l->l_map_start;
+ volatile long int *end = (volatile long int *) l->l_map_end;
+ while (p < end)
+ {
+ *p;
+ ++p;
+ }
+ }
+
+ xdlclose (l);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-link-map-contiguous-libc.c b/elf/tst-link-map-contiguous-libc.c
new file mode 100644
index 0000000000000000..eb5728c765ac3cfb
--- /dev/null
+++ b/elf/tst-link-map-contiguous-libc.c
@@ -0,0 +1,57 @@
+/* Check that the entire libc.so program image is readable if contiguous.
+ 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/>. */
+
+#include <gnu/lib-names.h>
+#include <link.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ struct link_map *l = xdlopen (LIBC_SO, RTLD_NOW);
+
+ /* The dynamic loader fills holes with PROT_NONE mappings. */
+ if (!l->l_contiguous)
+ FAIL_EXIT1 ("libc.so link map is not contiguous");
+
+ /* Direct probing does not work because not everything is readable
+ due to PROT_NONE mappings. */
+ int pagesize = getpagesize ();
+ ElfW(Addr) addr = l->l_map_start;
+ TEST_COMPARE (addr % pagesize, 0);
+ while (addr < l->l_map_end)
+ {
+ void *expected = (void *) addr;
+ void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
+ if (ptr == expected)
+ FAIL ("hole in libc.so memory image after %lu bytes",
+ (unsigned long int) (addr - l->l_map_start));
+ xmunmap (ptr, 1);
+ addr += pagesize;
+ }
+
+ xdlclose (l);
+
+ return 0;
+}
+#include <support/test-driver.c>
diff --git a/elf/tst-link-map-contiguous-main.c b/elf/tst-link-map-contiguous-main.c
new file mode 100644
index 0000000000000000..2d1a054f0fbb0855
--- /dev/null
+++ b/elf/tst-link-map-contiguous-main.c
@@ -0,0 +1,45 @@
+/* Check that the entire main program image is readable if contiguous.
+ 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/>. */
+
+#include <link.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+ struct link_map *l = xdlopen ("", RTLD_NOW);
+ if (!l->l_contiguous)
+ FAIL_UNSUPPORTED ("main link map is not contiguous");
+
+ /* This check only works if the kernel loaded the main program. The
+ dynamic loader replaces gaps with PROT_NONE mappings, resulting
+ in faults. */
+ volatile long int *p = (volatile long int *) l->l_map_start;
+ volatile long int *end = (volatile long int *) l->l_map_end;
+ while (p < end)
+ {
+ *p;
+ ++p;
+ }
+
+ xdlclose (l);
+
+ return 0;
+}
+#include <support/test-driver.c>

View File

@ -0,0 +1,41 @@
commit fca59375106e798911f3793768e94ee114542e3e
Author: Carlos O'Donell <carlos@redhat.com>
Date: Thu Jun 8 06:43:44 2023 -0400
ctype: Reformat Makefile.
Reflow and sort Makefile.
Code generation changes present due to link order changes.
No regressions on x86_64 and i686.
(cherry picked from commit 12956e0a330e3d90fc196f7d7a047ce613f78920)
diff --git a/ctype/Makefile b/ctype/Makefile
index 717d02012942e0b9..3e09938bd1bb1522 100644
--- a/ctype/Makefile
+++ b/ctype/Makefile
@@ -24,9 +24,18 @@ include ../Makeconfig
headers := ctype.h
-routines := ctype ctype-c99 ctype-extn ctype-c99_l ctype_l isctype
-aux := ctype-info
-
-tests := test_ctype
+routines := \
+ ctype \
+ ctype-c99 \
+ ctype-c99_l \
+ ctype-extn \
+ ctype_l \
+ isctype \
+ # routines
+aux := ctype-info
+
+tests := \
+ test_ctype \
+ # tests
include ../Rules

View File

@ -0,0 +1,296 @@
commit fbdf9680cc67d5646607c3d6fdc146fedc383a2a
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri May 16 19:53:09 2025 +0200
Remove <libc-tsd.h>
Use __thread variables directly instead. The macros do not save any
typing. It seems unlikely that a future port will lack __thread
variable support.
Some of the __libc_tsd_* variables are referenced from assembler
files, so keep their names. Previously, <libc-tls.h> included
<tls.h>, which in turn included <errno.h>, so a few direct includes
of <errno.h> are now required.
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
(cherry picked from commit 10a66a8e421b09682b774c795ef1da402235dddc)
diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c
index 9032547567b2c348..71d1c8e3b4660d54 100644
--- a/ctype/ctype-info.c
+++ b/ctype/ctype-info.c
@@ -19,20 +19,20 @@
#include <ctype.h>
#include <locale/localeinfo.h>
-__libc_tsd_define (, const uint16_t *, CTYPE_B)
-__libc_tsd_define (, const int32_t *, CTYPE_TOLOWER)
-__libc_tsd_define (, const int32_t *, CTYPE_TOUPPER)
+__thread const uint16_t * __libc_tsd_CTYPE_B;
+__thread const int32_t * __libc_tsd_CTYPE_TOLOWER;
+__thread const int32_t * __libc_tsd_CTYPE_TOUPPER;
void
__ctype_init (void)
{
- const uint16_t **bp = __libc_tsd_address (const uint16_t *, CTYPE_B);
- *bp = (const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS) + 128;
- const int32_t **up = __libc_tsd_address (const int32_t *, CTYPE_TOUPPER);
- *up = ((int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOUPPER) + 128);
- const int32_t **lp = __libc_tsd_address (const int32_t *, CTYPE_TOLOWER);
- *lp = ((int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOLOWER) + 128);
+ __libc_tsd_CTYPE_B
+ = ((const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS)) + 128;
+ __libc_tsd_CTYPE_TOUPPER
+ = ((const int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOUPPER)) + 128;
+ __libc_tsd_CTYPE_TOLOWER =
+ ((const int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOLOWER)) + 128;
}
libc_hidden_def (__ctype_init)
diff --git a/include/ctype.h b/include/ctype.h
index 493a6f80ce8e8b8e..e993adc86da43b7c 100644
--- a/include/ctype.h
+++ b/include/ctype.h
@@ -24,33 +24,32 @@ libc_hidden_proto (toupper)
NL_CURRENT_INDIRECT. */
# include "../locale/localeinfo.h"
-# include <libc-tsd.h>
# ifndef CTYPE_EXTERN_INLINE /* Used by ctype/ctype-info.c, which see. */
# define CTYPE_EXTERN_INLINE extern inline
# endif
-__libc_tsd_define (extern, const uint16_t *, CTYPE_B)
-__libc_tsd_define (extern, const int32_t *, CTYPE_TOUPPER)
-__libc_tsd_define (extern, const int32_t *, CTYPE_TOLOWER)
+extern __thread const uint16_t * __libc_tsd_CTYPE_B;
+extern __thread const int32_t * __libc_tsd_CTYPE_TOUPPER;
+extern __thread const int32_t * __libc_tsd_CTYPE_TOLOWER;
CTYPE_EXTERN_INLINE const uint16_t ** __attribute__ ((const))
__ctype_b_loc (void)
{
- return __libc_tsd_address (const uint16_t *, CTYPE_B);
+ return &__libc_tsd_CTYPE_B;
}
CTYPE_EXTERN_INLINE const int32_t ** __attribute__ ((const))
__ctype_toupper_loc (void)
{
- return __libc_tsd_address (const int32_t *, CTYPE_TOUPPER);
+ return &__libc_tsd_CTYPE_TOUPPER;
}
CTYPE_EXTERN_INLINE const int32_t ** __attribute__ ((const))
__ctype_tolower_loc (void)
{
- return __libc_tsd_address (const int32_t *, CTYPE_TOLOWER);
+ return &__libc_tsd_CTYPE_TOLOWER;
}
# ifndef __NO_CTYPE
diff --git a/include/rpc/rpc.h b/include/rpc/rpc.h
index f5cee6caef6284d2..936ea3cebb8101e1 100644
--- a/include/rpc/rpc.h
+++ b/include/rpc/rpc.h
@@ -3,8 +3,6 @@
# ifndef _ISOMAC
-#include <libc-tsd.h>
-
/* Now define the internal interfaces. */
extern unsigned long _create_xid (void);
@@ -47,7 +45,7 @@ extern void __rpc_thread_key_cleanup (void) attribute_hidden;
extern void __rpc_thread_destroy (void) attribute_hidden;
-__libc_tsd_define (extern, struct rpc_thread_variables *, RPC_VARS)
+extern __thread struct rpc_thread_variables *__libc_tsd_RPC_VARS;
#define RPC_THREAD_VARIABLE(x) (__rpc_thread_variables()->x)
diff --git a/locale/lc-ctype.c b/locale/lc-ctype.c
index c77ec51cb89b839d..70556acaf0dc69bb 100644
--- a/locale/lc-ctype.c
+++ b/locale/lc-ctype.c
@@ -64,12 +64,9 @@ _nl_postload_ctype (void)
in fact using the global locale. */
if (_NL_CURRENT_LOCALE == &_nl_global_locale)
{
- __libc_tsd_set (const uint16_t *, CTYPE_B,
- (void *) _nl_global_locale.__ctype_b);
- __libc_tsd_set (const int32_t *, CTYPE_TOUPPER,
- (void *) _nl_global_locale.__ctype_toupper);
- __libc_tsd_set (const int32_t *, CTYPE_TOLOWER,
- (void *) _nl_global_locale.__ctype_tolower);
+ __libc_tsd_CTYPE_B = _nl_global_locale.__ctype_b;
+ __libc_tsd_CTYPE_TOUPPER = _nl_global_locale.__ctype_toupper;
+ __libc_tsd_CTYPE_TOLOWER = _nl_global_locale.__ctype_tolower;
}
#include <shlib-compat.h>
diff --git a/locale/localeinfo.h b/locale/localeinfo.h
index ed698faef1b38003..bc8e92e4dca80d62 100644
--- a/locale/localeinfo.h
+++ b/locale/localeinfo.h
@@ -236,10 +236,8 @@ extern struct __locale_struct _nl_global_locale attribute_hidden;
/* This fetches the thread-local locale_t pointer, either one set with
uselocale or &_nl_global_locale. */
-#define _NL_CURRENT_LOCALE (__libc_tsd_get (locale_t, LOCALE))
-#include <libc-tsd.h>
-__libc_tsd_define (extern, locale_t, LOCALE)
-
+#define _NL_CURRENT_LOCALE __libc_tsd_LOCALE
+extern __thread locale_t __libc_tsd_LOCALE;
/* For static linking it is desireable to avoid always linking in the code
and data for every category when we can tell at link time that they are
diff --git a/locale/uselocale.c b/locale/uselocale.c
index 8136caf61b4673fb..0b247a77d5f47f81 100644
--- a/locale/uselocale.c
+++ b/locale/uselocale.c
@@ -34,7 +34,7 @@ __uselocale (locale_t newloc)
{
const locale_t locobj
= newloc == LC_GLOBAL_LOCALE ? &_nl_global_locale : newloc;
- __libc_tsd_set (locale_t, LOCALE, locobj);
+ __libc_tsd_LOCALE = locobj;
#ifdef NL_CURRENT_INDIRECT
/* Now we must update all the per-category thread-local variables to
@@ -62,11 +62,9 @@ __uselocale (locale_t newloc)
#endif
/* Update the special tsd cache of some locale data. */
- __libc_tsd_set (const uint16_t *, CTYPE_B, (void *) locobj->__ctype_b);
- __libc_tsd_set (const int32_t *, CTYPE_TOLOWER,
- (void *) locobj->__ctype_tolower);
- __libc_tsd_set (const int32_t *, CTYPE_TOUPPER,
- (void *) locobj->__ctype_toupper);
+ __libc_tsd_CTYPE_B = locobj->__ctype_b;
+ __libc_tsd_CTYPE_TOLOWER = locobj->__ctype_tolower;
+ __libc_tsd_CTYPE_TOUPPER = locobj->__ctype_toupper;
}
return oldloc == &_nl_global_locale ? LC_GLOBAL_LOCALE : oldloc;
diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c
index ab9fafb5ecb12f16..8db18f11b32c9433 100644
--- a/stdio-common/printf-parsemb.c
+++ b/stdio-common/printf-parsemb.c
@@ -17,6 +17,7 @@
<https://www.gnu.org/licenses/>. */
#include <ctype.h>
+#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
diff --git a/string/strerror.c b/string/strerror.c
index 107d9d39c287bed4..efa4e903ead00a47 100644
--- a/string/strerror.c
+++ b/string/strerror.c
@@ -21,5 +21,5 @@
char *
strerror (int errnum)
{
- return __strerror_l (errnum, __libc_tsd_get (locale_t, LOCALE));
+ return __strerror_l (errnum, __libc_tsd_LOCALE);
}
diff --git a/sunrpc/rpc_thread.c b/sunrpc/rpc_thread.c
index a04b7ec47fa4760c..e20f0a62302eb675 100644
--- a/sunrpc/rpc_thread.c
+++ b/sunrpc/rpc_thread.c
@@ -3,7 +3,6 @@
#include <assert.h>
#include <libc-lock.h>
-#include <libc-tsd.h>
#include <shlib-compat.h>
#include <libc-symbols.h>
diff --git a/sysdeps/generic/libc-tsd.h b/sysdeps/generic/libc-tsd.h
deleted file mode 100644
index ac0e99e14b1bcb90..0000000000000000
--- a/sysdeps/generic/libc-tsd.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* libc-internal interface for thread-specific data. Stub or TLS version.
- Copyright (C) 1998-2024 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 _GENERIC_LIBC_TSD_H
-#define _GENERIC_LIBC_TSD_H 1
-
-/* This file defines the following macros for accessing a small fixed
- set of thread-specific `void *' data used only internally by libc.
-
- __libc_tsd_define(CLASS, TYPE, KEY) -- Define or declare a datum with TYPE
- for KEY. CLASS can be `static' for
- keys used in only one source file,
- empty for global definitions, or
- `extern' for global declarations.
- __libc_tsd_address(TYPE, KEY) -- Return the `TYPE *' pointing to
- the current thread's datum for KEY.
- __libc_tsd_get(TYPE, KEY) -- Return the `TYPE' datum for KEY.
- __libc_tsd_set(TYPE, KEY, VALUE) -- Set the datum for KEY to VALUE.
-
- The set of available KEY's will usually be provided as an enum,
- and contains (at least):
- _LIBC_TSD_KEY_MALLOC
- _LIBC_TSD_KEY_DL_ERROR
- _LIBC_TSD_KEY_RPC_VARS
- All uses must be the literal _LIBC_TSD_* name in the __libc_tsd_* macros.
- Some implementations may not provide any enum at all and instead
- using string pasting in the macros. */
-
-#include <tls.h>
-
-/* When full support for __thread variables is available, this interface is
- just a trivial wrapper for it. Without TLS, this is the generic/stub
- implementation for wholly single-threaded systems.
-
- We don't define an enum for the possible key values, because the KEYs
- translate directly into variables by macro magic. */
-
-#define __libc_tsd_define(CLASS, TYPE, KEY) \
- CLASS __thread TYPE __libc_tsd_##KEY attribute_tls_model_ie;
-
-#define __libc_tsd_address(TYPE, KEY) (&__libc_tsd_##KEY)
-#define __libc_tsd_get(TYPE, KEY) (__libc_tsd_##KEY)
-#define __libc_tsd_set(TYPE, KEY, VALUE) (__libc_tsd_##KEY = (VALUE))
-
-#endif /* libc-tsd.h */
diff --git a/time/strftime_l.c b/time/strftime_l.c
index 77adec905007d53a..066c839c2feccdc1 100644
--- a/time/strftime_l.c
+++ b/time/strftime_l.c
@@ -40,6 +40,7 @@
#endif
#include <ctype.h>
+#include <errno.h>
#include <sys/types.h> /* Some systems define `time_t' here. */
#ifdef TIME_WITH_SYS_TIME

View File

@ -0,0 +1,67 @@
commit 25c537c3b3933663642874e332c73c6f65e3ddea
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri May 16 19:53:09 2025 +0200
Use proper extern declaration for _nl_C_LC_CTYPE_{class,toupper,tolower}
The existing initializers already contain explicit casts. Keep them
due to int/uint32_t mismatch.
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
(cherry picked from commit e0c0f856f58ceb68800a964c36c15c606e7a8c4c)
diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c
index 71d1c8e3b4660d54..94e312d91ff76323 100644
--- a/ctype/ctype-info.c
+++ b/ctype/ctype-info.c
@@ -41,10 +41,7 @@ libc_hidden_def (__ctype_init)
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
/* Defined in locale/C-ctype.c. */
-extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_class32[] attribute_hidden;
-extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
-extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_class_upper[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_class_lower[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_class_alpha[] attribute_hidden;
diff --git a/include/ctype.h b/include/ctype.h
index e993adc86da43b7c..ae078a63d355af61 100644
--- a/include/ctype.h
+++ b/include/ctype.h
@@ -63,6 +63,11 @@ __ctype_tolower_loc (void)
# define __isdigit_l(c, l) ({ int __c = (c); __c >= '0' && __c <= '9'; })
# endif /* Not __NO_CTYPE. */
+/* For use in initializers. */
+extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
+extern const uint32_t _nl_C_LC_CTYPE_toupper[] attribute_hidden;
+extern const uint32_t _nl_C_LC_CTYPE_tolower[] attribute_hidden;
+
# endif /* IS_IN (libc). */
#endif /* Not _ISOMAC. */
diff --git a/locale/xlocale.c b/locale/xlocale.c
index f2b9d03303e6653d..d11c1cbf8c65ad54 100644
--- a/locale/xlocale.c
+++ b/locale/xlocale.c
@@ -18,18 +18,13 @@
#include <locale.h>
#include "localeinfo.h"
+#include <ctype.h>
#define DEFINE_CATEGORY(category, category_name, items, a) \
extern struct __locale_data _nl_C_##category;
#include "categories.def"
#undef DEFINE_CATEGORY
-/* Defined in locale/C-ctype.c. */
-extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
-extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
-extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden;
-
-
const struct __locale_struct _nl_C_locobj attribute_hidden =
{
.__locales =

View File

@ -0,0 +1,198 @@
commit c11950503fbb8b5885a0400d1a7ba83a80878e53
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri May 16 19:53:09 2025 +0200
ctype: Fallback initialization of TLS using relocations (bug 19341, bug 32483)
This ensures that the ctype data pointers in TLS are valid
in secondary namespaces even without initialization via
__ctype_init.
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
(cherry picked from commit 2745db8dd3ec31045acd761b612516490085bc20)
diff --git a/ctype/Makefile b/ctype/Makefile
index 3e09938bd1bb1522..b7cd5f2282b4511c 100644
--- a/ctype/Makefile
+++ b/ctype/Makefile
@@ -36,6 +36,23 @@ aux := ctype-info
tests := \
test_ctype \
+ tst-ctype-tls-dlmopen \
+ tst-ctype-tls-dlopen-static \
# tests
+tests-static := \
+ tst-ctype-tls-dlopen-static \
+ # tests-static
+
+modules-names := \
+ tst-ctype-tls-mod \
+ # modules-names
+
include ../Rules
+
+$(objpfx)tst-ctype-tls-dlmopen: $(shared-thread-library)
+$(objpfx)tst-ctype-tls-dlmopen.out: $(objpfx)tst-ctype-tls-mod.so
+$(objpfx)tst-ctype-tls-dlopen-static: $(static-thread-library)
+$(objpfx)tst-ctype-tls-dlopen-static.out: $(objpfx)tst-ctype-tls-mod.so
+tst-ctype-tls-dlopen-static-ENV = \
+ LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx):$(common-objpfx)elf
diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c
index 94e312d91ff76323..621bd4239c8b4c21 100644
--- a/ctype/ctype-info.c
+++ b/ctype/ctype-info.c
@@ -19,9 +19,17 @@
#include <ctype.h>
#include <locale/localeinfo.h>
-__thread const uint16_t * __libc_tsd_CTYPE_B;
-__thread const int32_t * __libc_tsd_CTYPE_TOLOWER;
-__thread const int32_t * __libc_tsd_CTYPE_TOUPPER;
+/* Fallback initialization using relocations. See the _nl_C_locobj
+ initializers in locale/xlocale.c. Usually, this is overwritten by
+ __ctype_init before user code runs, but this does not happen for
+ threads in secondary namespaces. With the initializers, secondary
+ namespaces at least get locale data from the C locale. */
+__thread const uint16_t * __libc_tsd_CTYPE_B
+ = (const uint16_t *) _nl_C_LC_CTYPE_class + 128;
+__thread const int32_t * __libc_tsd_CTYPE_TOLOWER
+ = (const int32_t *) _nl_C_LC_CTYPE_tolower + 128;
+__thread const int32_t * __libc_tsd_CTYPE_TOUPPER
+ = (const int32_t *) _nl_C_LC_CTYPE_toupper + 128;
void
diff --git a/ctype/tst-ctype-tls-dlmopen.c b/ctype/tst-ctype-tls-dlmopen.c
new file mode 100644
index 0000000000000000..f7eeb65551344b72
--- /dev/null
+++ b/ctype/tst-ctype-tls-dlmopen.c
@@ -0,0 +1,2 @@
+#define DO_STATIC_TEST 0
+#include "tst-ctype-tls-skeleton.c"
diff --git a/ctype/tst-ctype-tls-dlopen-static.c b/ctype/tst-ctype-tls-dlopen-static.c
new file mode 100644
index 0000000000000000..c2c09c362cc95906
--- /dev/null
+++ b/ctype/tst-ctype-tls-dlopen-static.c
@@ -0,0 +1,2 @@
+#define DO_STATIC_TEST 1
+#include "tst-ctype-tls-skeleton.c"
diff --git a/ctype/tst-ctype-tls-mod.c b/ctype/tst-ctype-tls-mod.c
new file mode 100644
index 0000000000000000..52cbb9dcb67e1800
--- /dev/null
+++ b/ctype/tst-ctype-tls-mod.c
@@ -0,0 +1,37 @@
+/* Wrappers for <ctype.h> macros in a secondary namespace.
+ 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/>. */
+
+#include <ctype.h>
+
+int
+my_isalpha (int ch)
+{
+ return isalpha (ch);
+}
+
+int
+my_toupper (int ch)
+{
+ return toupper (ch);
+}
+
+int
+my_tolower (int ch)
+{
+ return tolower (ch);
+}
diff --git a/ctype/tst-ctype-tls-skeleton.c b/ctype/tst-ctype-tls-skeleton.c
new file mode 100644
index 0000000000000000..8c53e35899f12b8f
--- /dev/null
+++ b/ctype/tst-ctype-tls-skeleton.c
@@ -0,0 +1,67 @@
+/* Test that <ctype.h> in a secondary namespace works.
+ 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/>. */
+
+/* Before this file is included, define DO_STATIC_TEST to 0 or 1.
+ With 0, dlmopen is used for the test. With 1, dlopen is used. */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+
+static int (*my_isalpha) (int);
+static int (*my_toupper) (int);
+static int (*my_tolower) (int);
+
+static void *
+checks (void *ignore)
+{
+ TEST_VERIFY (my_isalpha ('a'));
+ TEST_VERIFY (!my_isalpha ('0'));
+ TEST_COMPARE (my_toupper ('a'), 'A');
+ TEST_COMPARE (my_toupper ('A'), 'A');
+ TEST_COMPARE (my_tolower ('a'), 'a');
+ TEST_COMPARE (my_tolower ('A'), 'a');
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ char *dso = xasprintf ("%s/ctype/tst-ctype-tls-mod.so", support_objdir_root);
+#if DO_STATIC_TEST
+ void *handle = xdlopen (dso, RTLD_LAZY);
+#else
+ void *handle = xdlmopen (LM_ID_NEWLM, dso, RTLD_LAZY);
+#endif
+ my_isalpha = xdlsym (handle, "my_isalpha");
+ my_toupper = xdlsym (handle, "my_toupper");
+ my_tolower = xdlsym (handle, "my_tolower");
+
+ checks (NULL);
+ xpthread_join (xpthread_create (NULL, checks, NULL));
+
+ xdlclose (handle);
+ free (dso);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,40 @@
commit 20d2d69a2fcb3357127bea4536c8c85b183dc3b9
Author: Jens Remus <jremus@linux.ibm.com>
Date: Fri Jul 25 15:40:03 2025 +0200
Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables [BZ #33234]
Commit 10a66a8e421b ("Remove <libc-tsd.h>") removed the TLS initial-exec
(IE) model attribute from the __libc_tsd_CTYPE_* thread variable declarations
and definitions. Commit a894f04d8776 ("Optimize __libc_tsd_* thread
variable access") restored it on declarations.
Restore the TLS initial-exec model attribute on __libc_tsd_CTYPE_* thread
variable definitions.
This resolves test tst-locale1 failure on s390 32-bit, when using a
GNU linker without the fix from GNU binutils commit aefebe82dc89
("IBM zSystems: Fix offset relative to static TLS").
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit e5363e6f460c2d58809bf10fc96d70fd1ef8b5b2)
diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c
index 621bd4239c8b4c21..b6cdf7eb667a7118 100644
--- a/ctype/ctype-info.c
+++ b/ctype/ctype-info.c
@@ -24,11 +24,11 @@
__ctype_init before user code runs, but this does not happen for
threads in secondary namespaces. With the initializers, secondary
namespaces at least get locale data from the C locale. */
-__thread const uint16_t * __libc_tsd_CTYPE_B
+__thread const uint16_t * __libc_tsd_CTYPE_B attribute_tls_model_ie
= (const uint16_t *) _nl_C_LC_CTYPE_class + 128;
-__thread const int32_t * __libc_tsd_CTYPE_TOLOWER
+__thread const int32_t * __libc_tsd_CTYPE_TOLOWER attribute_tls_model_ie
= (const int32_t *) _nl_C_LC_CTYPE_tolower + 128;
-__thread const int32_t * __libc_tsd_CTYPE_TOUPPER
+__thread const int32_t * __libc_tsd_CTYPE_TOUPPER attribute_tls_model_ie
= (const int32_t *) _nl_C_LC_CTYPE_toupper + 128;

View File

@ -0,0 +1,544 @@
commit d1c1f78e9eb9ff5e8eeae21ec9a879b7d0095c2e
Author: Joe Ramsay <Joe.Ramsay@arm.com>
Date: Fri Jan 3 19:13:36 2025 +0000
math: Remove no-mathvec flag
More routines are to follow, some of which hit many failures in the
current testsuite due to wrong sign of zero (mathvec routines are not
required to get this right). Instead of disabling a large number of
tests, change the failure condition such that, for vector routines,
tests pass as long as computed == expected == 0.0, regardless of sign.
Affected tests (vector tests for expm1, log1p, sin, tan and tanh) all
still pass.
(cherry picked from commit 939e770e0196ebd763cacc602421b76d62df0798)
diff --git a/math/auto-libm-test-in b/math/auto-libm-test-in
index d728f9777015d3b9..5a690023e9a675cb 100644
--- a/math/auto-libm-test-in
+++ b/math/auto-libm-test-in
@@ -5354,7 +5354,7 @@ exp2 -0x4.8ce878p-4
exp2 0xf.93d18bf7be8d272p-4
expm1 0
-expm1 -0 no-mathvec
+expm1 -0
expm1 1
expm1 0.75
expm1 2
@@ -5419,7 +5419,7 @@ expm1 -0x1p-100
expm1 0x1p-600
expm1 -0x1p-600
expm1 0x1p-10000
-expm1 -0x1p-10000 no-mathvec
+expm1 -0x1p-10000
expm1 0xe.4152ac57cd1ea7ap-60
expm1 0x6.660247486aed8p-4
expm1 0x6.289a78p-4
@@ -6577,7 +6577,7 @@ log10 0xf.bf1b2p-4
log10 0x1.6b5f7ap+96
log1p 0
-log1p -0 no-mathvec
+log1p -0
log1p e-1
log1p -0.25
log1p -0.875
@@ -7318,7 +7318,7 @@ pow 0x1.7ac7cp+5 23
pow -0x1.7ac7cp+5 23
sin 0
-sin -0 no-mathvec
+sin -0
sin pi/6
sin -pi/6
sin pi/2
@@ -7655,7 +7655,7 @@ sqrt min
sqrt min_subnorm
tan 0
-tan -0 no-mathvec
+tan -0
tan pi/4
tan pi/2
tan -pi/2
diff --git a/math/auto-libm-test-out-expm1 b/math/auto-libm-test-out-expm1
index 91da41b7f604a5a1..8483455801221aac 100644
--- a/math/auto-libm-test-out-expm1
+++ b/math/auto-libm-test-out-expm1
@@ -23,31 +23,31 @@ expm1 0
= expm1 tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= expm1 towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= expm1 upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-expm1 -0 no-mathvec
-= expm1 downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+expm1 -0
+= expm1 downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
expm1 1
= expm1 downward binary32 0x1p+0 : 0x1.b7e15p+0 : inexact-ok
= expm1 tonearest binary32 0x1p+0 : 0x1.b7e152p+0 : inexact-ok
@@ -1880,87 +1880,87 @@ expm1 0x1p-10000
= expm1 tonearest binary128 0x1p-10000 : 0x1p-10000 : inexact-ok
= expm1 towardzero binary128 0x1p-10000 : 0x1p-10000 : inexact-ok
= expm1 upward binary128 0x1p-10000 : 0x1.0000000000000000000000000001p-10000 : inexact-ok
-expm1 -0x1p-10000 no-mathvec
-= expm1 downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary32 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 tonearest binary32 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 towardzero binary32 -0x8p-152 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 upward binary32 -0x8p-152 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 downward binary64 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest binary64 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : no-mathvec inexact-ok
-= expm1 upward binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : no-mathvec inexact-ok
-= expm1 downward intel96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : no-mathvec inexact-ok
-= expm1 downward ibm128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest ibm128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : no-mathvec inexact-ok
-= expm1 upward ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : no-mathvec inexact-ok
-= expm1 downward binary64 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 tonearest binary64 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 towardzero binary64 -0x4p-1076 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 upward binary64 -0x4p-1076 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 downward intel96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : no-mathvec inexact-ok
-= expm1 downward ibm128 -0x4p-1076 : -0x4p-1076 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
-= expm1 tonearest ibm128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 towardzero ibm128 -0x4p-1076 : -0x0p+0 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
-= expm1 upward ibm128 -0x4p-1076 : -0x0p+0 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
-= expm1 downward intel96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : no-mathvec inexact-ok
+expm1 -0x1p-10000
+= expm1 downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary32 -0x8p-152 : -0x8p-152 : inexact-ok underflow errno-erange-ok
+= expm1 tonearest binary32 -0x8p-152 : -0x8p-152 : inexact-ok underflow errno-erange-ok
+= expm1 towardzero binary32 -0x8p-152 : -0x0p+0 : inexact-ok underflow errno-erange-ok
+= expm1 upward binary32 -0x8p-152 : -0x0p+0 : inexact-ok underflow errno-erange-ok
+= expm1 downward binary64 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest binary64 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : inexact-ok
+= expm1 upward binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : inexact-ok
+= expm1 downward intel96 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest intel96 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok
+= expm1 upward intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok
+= expm1 downward m68k96 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest m68k96 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok
+= expm1 upward m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok
+= expm1 downward binary128 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest binary128 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : inexact-ok
+= expm1 upward binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : inexact-ok
+= expm1 downward ibm128 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest ibm128 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : inexact-ok
+= expm1 upward ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : inexact-ok
+= expm1 downward binary64 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok
+= expm1 tonearest binary64 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok
+= expm1 towardzero binary64 -0x4p-1076 : -0x0p+0 : inexact-ok underflow errno-erange-ok
+= expm1 upward binary64 -0x4p-1076 : -0x0p+0 : inexact-ok underflow errno-erange-ok
+= expm1 downward intel96 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 tonearest intel96 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 towardzero intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok
+= expm1 upward intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok
+= expm1 downward m68k96 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 tonearest m68k96 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 towardzero m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok
+= expm1 upward m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok
+= expm1 downward binary128 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 tonearest binary128 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 towardzero binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : inexact-ok
+= expm1 upward binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : inexact-ok
+= expm1 downward ibm128 -0x4p-1076 : -0x4p-1076 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
+= expm1 tonearest ibm128 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok
+= expm1 towardzero ibm128 -0x4p-1076 : -0x0p+0 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
+= expm1 upward ibm128 -0x4p-1076 : -0x0p+0 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
+= expm1 downward intel96 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 tonearest intel96 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 towardzero intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok
+= expm1 upward intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok
+= expm1 downward m68k96 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 tonearest m68k96 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 towardzero m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok
+= expm1 upward m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok
+= expm1 downward binary128 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 tonearest binary128 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 towardzero binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : inexact-ok
+= expm1 upward binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : inexact-ok
expm1 0xe.4152ac57cd1ea7ap-60
= expm1 downward binary32 0xe.4152bp-60 : 0xe.4152bp-60 : inexact-ok
= expm1 tonearest binary32 0xe.4152bp-60 : 0xe.4152bp-60 : inexact-ok
diff --git a/math/auto-libm-test-out-log1p b/math/auto-libm-test-out-log1p
index f83241f51ad9db8b..f7d3b35e6d4465c4 100644
--- a/math/auto-libm-test-out-log1p
+++ b/math/auto-libm-test-out-log1p
@@ -23,31 +23,31 @@ log1p 0
= log1p tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= log1p towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= log1p upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-log1p -0 no-mathvec
-= log1p downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+log1p -0
+= log1p downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
log1p e-1
= log1p downward binary32 0x1.b7e152p+0 : 0x1p+0 : inexact-ok
= log1p tonearest binary32 0x1.b7e152p+0 : 0x1p+0 : inexact-ok
diff --git a/math/auto-libm-test-out-sin b/math/auto-libm-test-out-sin
index e1f684528316dde5..f1d21b179c955eb7 100644
--- a/math/auto-libm-test-out-sin
+++ b/math/auto-libm-test-out-sin
@@ -23,31 +23,31 @@ sin 0
= sin tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= sin towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= sin upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-sin -0 no-mathvec
-= sin downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+sin -0
+= sin downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
sin pi/6
= sin downward binary32 0x8.60a92p-4 : 0x8p-4 : inexact-ok
= sin tonearest binary32 0x8.60a92p-4 : 0x8p-4 : inexact-ok
diff --git a/math/auto-libm-test-out-tan b/math/auto-libm-test-out-tan
index f46fdc7ec62075f2..7d00d03e1da81b18 100644
--- a/math/auto-libm-test-out-tan
+++ b/math/auto-libm-test-out-tan
@@ -23,31 +23,31 @@ tan 0
= tan tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= tan towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= tan upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-tan -0 no-mathvec
-= tan downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+tan -0
+= tan downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
tan pi/4
= tan downward binary32 0xc.90fdbp-4 : 0x1p+0 : inexact-ok
= tan tonearest binary32 0xc.90fdbp-4 : 0x1p+0 : inexact-ok
diff --git a/math/gen-auto-libm-tests.c b/math/gen-auto-libm-tests.c
index c35242b356821eed..48227248e4aebc90 100644
--- a/math/gen-auto-libm-tests.c
+++ b/math/gen-auto-libm-tests.c
@@ -96,8 +96,7 @@
zero and infinite results should be ignored; "xfail" indicates the
test is disabled as expected to produce incorrect results,
"xfail-rounding" indicates the test is disabled only in rounding
- modes other than round-to-nearest; "no-mathvec" indicates the test
- is disabled in vector math libraries. Otherwise, test flags are of
+ modes other than round-to-nearest. Otherwise, test flags are of
the form "spurious-<exception>" and "missing-<exception>", for any
exception ("overflow", "underflow", "inexact", "invalid",
"divbyzero"), "spurious-errno" and "missing-errno", to indicate
@@ -353,7 +352,6 @@ typedef enum
flag_missing_overflow,
flag_missing_underflow,
flag_missing_errno,
- flag_no_mathvec,
num_input_flag_types,
flag_first_flag = 0,
flag_spurious_first = flag_spurious_divbyzero,
@@ -379,7 +377,6 @@ static const char *const input_flags[num_input_flag_types] =
"missing-overflow",
"missing-underflow",
"missing-errno",
- "no-mathvec",
};
/* An input flag, possibly conditional. */
@@ -2052,7 +2049,6 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf,
{
case flag_ignore_zero_inf_sign:
case flag_xfail:
- case flag_no_mathvec:
if (fprintf (fp, " %s%s",
input_flags[it->flags[i].type],
(it->flags[i].cond
diff --git a/math/gen-libm-test.py b/math/gen-libm-test.py
index 397dbd325930841f..6e8bb564379e2117 100755
--- a/math/gen-libm-test.py
+++ b/math/gen-libm-test.py
@@ -93,8 +93,7 @@ BEAUTIFY_MAP = {'minus_zero': '-0',
# Flags in auto-libm-test-out that map directly to C flags.
FLAGS_SIMPLE = {'ignore-zero-inf-sign': 'IGNORE_ZERO_INF_SIGN',
- 'xfail': 'XFAIL_TEST',
- 'no-mathvec': 'NO_TEST_MATHVEC'}
+ 'xfail': 'XFAIL_TEST'}
# Exceptions in auto-libm-test-out, and their corresponding C flags
# for being required, OK or required to be absent.
diff --git a/math/libm-test-support.c b/math/libm-test-support.c
index 0796f9d4956e3818..3fecd87064666f94 100644
--- a/math/libm-test-support.c
+++ b/math/libm-test-support.c
@@ -776,7 +776,7 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
ulps = ULPDIFF (computed, expected);
set_max_error (ulps, curr_max_error);
print_diff = 1;
- if ((exceptions & IGNORE_ZERO_INF_SIGN) == 0
+ if (((exceptions & IGNORE_ZERO_INF_SIGN) == 0) && !flag_test_mathvec
&& computed == 0.0 && expected == 0.0
&& signbit(computed) != signbit (expected))
ok = 0;

View File

@ -0,0 +1,64 @@
commit 62ff85fd09ff648183af4265f07dace2879e6d42
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Jul 28 12:18:22 2025 -0700
x86-64: Add GLIBC_ABI_GNU2_TLS version [BZ #33129]
Programs and shared libraries compiled with -mtls-dialect=gnu2 may fail
silently at run-time against glibc without the GNU2 TLS run-time fix
for:
https://sourceware.org/bugzilla/show_bug.cgi?id=31372
Add GLIBC_ABI_GNU2_TLS version to indicate that glibc has the working
GNU2 TLS run-time. Linker can add the GLIBC_ABI_GNU2_TLS version to
binaries which depend on the working GNU2 TLS run-time:
https://sourceware.org/bugzilla/show_bug.cgi?id=33130
so that such programs and shared libraries will fail to load and run at
run-time against libc.so without the GLIBC_ABI_GNU2_TLS version, instead
of fail silently at random.
This fixes BZ #33129.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit 9df8fa397d515dc86ff5565f6c45625e672d539e)
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index 08ec882159990e97..af978601657c2129 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -209,6 +209,15 @@ LDFLAGS-tst-plt-rewrite2 = -Wl,-z,now
LDFLAGS-tst-plt-rewritemod2.so = -Wl,-z,now,-z,undefs
tst-plt-rewrite2-ENV = GLIBC_TUNABLES=glibc.cpu.plt_rewrite=2
$(objpfx)tst-plt-rewrite2: $(objpfx)tst-plt-rewritemod2.so
+
+tests-special += $(objpfx)check-gnu2-tls.out
+
+$(objpfx)check-gnu2-tls.out: $(common-objpfx)libc.so
+ LC_ALL=C $(READELF) -V -W $< \
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
+ | grep GLIBC_ABI_GNU2_TLS > $@; \
+ $(evaluate-test)
+generated += check-gnu2-tls.out
endif
test-internal-extras += tst-gnu2-tls2mod1
diff --git a/sysdeps/x86_64/Versions b/sysdeps/x86_64/Versions
index e94758b23643a905..a63c11bcb25adf48 100644
--- a/sysdeps/x86_64/Versions
+++ b/sysdeps/x86_64/Versions
@@ -5,6 +5,11 @@ libc {
GLIBC_2.13 {
__fentry__;
}
+ GLIBC_ABI_GNU2_TLS {
+ # This symbol is used only for empty version map and will be removed
+ # by scripts/versions.awk.
+ __placeholder_only_for_empty_version_map;
+ }
}
libm {
GLIBC_2.1 {

View File

@ -0,0 +1,76 @@
commit 269e89bd8d25a0659c6c963a509e152faefd6ba2
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Aug 14 07:03:20 2025 -0700
x86-64: Add GLIBC_ABI_DT_X86_64_PLT [BZ #33212]
When the linker -z mark-plt option is used to add DT_X86_64_PLT,
DT_X86_64_PLTSZ and DT_X86_64_PLTENT, the r_addend field of the
R_X86_64_JUMP_SLOT relocation stores the offset of the indirect
branch instruction. However, glibc versions without the commit:
commit f8587a61892cbafd98ce599131bf4f103466f084
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Fri May 20 19:21:48 2022 -0700
x86-64: Ignore r_addend for R_X86_64_GLOB_DAT/R_X86_64_JUMP_SLOT
According to x86-64 psABI, r_addend should be ignored for R_X86_64_GLOB_DAT
and R_X86_64_JUMP_SLOT. Since linkers always set their r_addends to 0, we
can ignore their r_addends.
Reviewed-by: Fangrui Song <maskray@google.com>
won't ignore the r_addend value in the R_X86_64_JUMP_SLOT relocation.
Such programs and shared libraries will fail at run-time randomly.
Add GLIBC_ABI_DT_X86_64_PLT version to indicate that glibc is compatible
with DT_X86_64_PLT.
The linker can add the glibc GLIBC_ABI_DT_X86_64_PLT version dependency
whenever -z mark-plt is passed to the linker. The resulting programs and
shared libraries will fail to load at run-time against libc.so without the
GLIBC_ABI_DT_X86_64_PLT version, instead of fail randomly.
This fixes BZ #33212.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit 399384e0c8193e31aea014220ccfa24300ae5938)
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index af978601657c2129..579bb33ada0e5f16 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -210,6 +210,15 @@ LDFLAGS-tst-plt-rewritemod2.so = -Wl,-z,now,-z,undefs
tst-plt-rewrite2-ENV = GLIBC_TUNABLES=glibc.cpu.plt_rewrite=2
$(objpfx)tst-plt-rewrite2: $(objpfx)tst-plt-rewritemod2.so
+tests-special += $(objpfx)check-dt-x86-64-plt.out
+
+$(objpfx)check-dt-x86-64-plt.out: $(common-objpfx)libc.so
+ LC_ALL=C $(READELF) -V -W $< \
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
+ | grep GLIBC_ABI_DT_X86_64_PLT > $@; \
+ $(evaluate-test)
+generated += check-dt-x86-64-plt.out
+
tests-special += $(objpfx)check-gnu2-tls.out
$(objpfx)check-gnu2-tls.out: $(common-objpfx)libc.so
diff --git a/sysdeps/x86_64/Versions b/sysdeps/x86_64/Versions
index a63c11bcb25adf48..0a759029e5a00cf1 100644
--- a/sysdeps/x86_64/Versions
+++ b/sysdeps/x86_64/Versions
@@ -10,6 +10,11 @@ libc {
# by scripts/versions.awk.
__placeholder_only_for_empty_version_map;
}
+ GLIBC_ABI_DT_X86_64_PLT {
+ # This symbol is used only for empty version map and will be removed
+ # by scripts/versions.awk.
+ __placeholder_only_for_empty_version_map;
+ }
}
libm {
GLIBC_2.1 {

View File

@ -0,0 +1,103 @@
commit 9fa7cc6a0b388ed16cf8a8976de5f5882882d503
Author: Adam Sampson <ats@offog.org>
Date: Mon May 6 18:16:32 2024 +0100
ldconfig: Move endswithn into a new header file
is_gdb_python_file is doing a similar test, so it can use this helper
function as well.
Signed-off-by: Adam Sampson <ats@offog.org>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit ed2b8d3a866eb37e069f6a71bdf10421cd4c5e54)
diff --git a/elf/endswith.h b/elf/endswith.h
new file mode 100644
index 0000000000000000..c6430c48be0c1071
--- /dev/null
+++ b/elf/endswith.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2023-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+#ifndef _ENDSWITH_H
+#define _ENDSWITH_H
+
+#include <string.h>
+
+/* Return true if the N bytes at NAME end with with the characters in
+ the string SUFFIX. (NAME[N + 1] does not have to be a null byte.)
+ Expected to be called with a string literal for SUFFIX. */
+static inline bool
+endswithn (const char *name, size_t n, const char *suffix)
+{
+ return (n >= strlen (suffix)
+ && memcmp (name + n - strlen (suffix), suffix,
+ strlen (suffix)) == 0);
+}
+
+#endif /* _ENDSWITH_H */
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index b64c54b53e1aa5bf..0f3ef707dd2f721d 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -40,6 +40,7 @@
#include <libgen.h>
#include <ldconfig.h>
+#include <endswith.h>
#include <dl-cache.h>
#include <dl-hwcaps.h>
#include <dl-is_dso.h>
@@ -661,17 +662,6 @@ struct dlib_entry
struct dlib_entry *next;
};
-/* Return true if the N bytes at NAME end with with the characters in
- the string SUFFIX. (NAME[N + 1] does not have to be a null byte.)
- Expected to be called with a string literal for SUFFIX. */
-static inline bool
-endswithn (const char *name, size_t n, const char *suffix)
-{
- return (n >= strlen (suffix)
- && memcmp (name + n - strlen (suffix), suffix,
- strlen (suffix)) == 0);
-}
-
/* Skip some temporary DSO files. These files may be partially written
and lead to ldconfig crashes when examined. */
static bool
diff --git a/elf/readlib.c b/elf/readlib.c
index 4d67c7413649be30..32e8b8eb2298c9dd 100644
--- a/elf/readlib.c
+++ b/elf/readlib.c
@@ -33,6 +33,7 @@
#include <gnu/lib-names.h>
#include <ldconfig.h>
+#include <endswith.h>
#define Elf32_CLASS ELFCLASS32
#define Elf64_CLASS ELFCLASS64
@@ -48,7 +49,7 @@ static bool
is_gdb_python_file (const char *name)
{
size_t len = strlen (name);
- return len > 7 && strcmp (name + len - 7, "-gdb.py") == 0;
+ return endswithn (name, len, "-gdb.py");
}
/* Returns 0 if everything is ok, != 0 in case of error. */

View File

@ -0,0 +1,242 @@
commit 6917fde6f9623d0521a9f16c8f10c94ab0f2e4ba
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Oct 25 16:50:10 2024 +0200
elf: Run constructors on cyclic recursive dlopen (bug 31986)
This is conceptually similar to the reported bug, but does not
depend on auditing. The fix is simple: just complete execution
of the constructors. This exposed the fact that the link map
for statically linked executables does not have l_init_called
set, even though constructors have run.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 9897ced8e78db5d813166a7ccccfd5a42c69ef20)
diff --git a/elf/Makefile b/elf/Makefile
index 3085a0844c6604fe..7690ee9edc0b0c9a 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -414,6 +414,7 @@ tests += \
tst-dlmopen1 \
tst-dlmopen3 \
tst-dlmopen4 \
+ tst-dlopen-recurse \
tst-dlopen-self \
tst-dlopen-tlsmodid \
tst-dlopen-tlsreinit1 \
@@ -858,6 +859,8 @@ modules-names += \
tst-dlmopen-twice-mod1 \
tst-dlmopen-twice-mod2 \
tst-dlmopen1mod \
+ tst-dlopen-recursemod1 \
+ tst-dlopen-recursemod2 \
tst-dlopen-sgid-mod \
tst-dlopen-tlsreinitmod1 \
tst-dlopen-tlsreinitmod2 \
@@ -3145,3 +3148,6 @@ $(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
+
+$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
+$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 8556e7bd2fb0b40e..5139d276e04a5d85 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -601,6 +601,14 @@ dl_open_worker_begin (void *a)
= _dl_debug_update (args->nsid)->r_state;
assert (r_state == RT_CONSISTENT);
+ /* Do not return without calling the (supposedly new) map's
+ constructor. This case occurs if a dependency of a directly
+ opened map has a constructor that calls dlopen again on the
+ initially opened map. The new map is initialized last, so
+ checking only it is enough. */
+ if (!new->l_init_called)
+ _dl_catch_exception (NULL, call_dl_init, args);
+
return;
}
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 451932dd03e971b8..94e8197c632c11c8 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -99,6 +99,7 @@ static struct link_map _dl_main_map =
.l_used = 1,
.l_tls_offset = NO_TLS_OFFSET,
.l_serial = 1,
+ .l_init_called = 1,
};
/* Namespace information. */
diff --git a/elf/tst-dlopen-recurse.c b/elf/tst-dlopen-recurse.c
new file mode 100644
index 0000000000000000..c7fb379d373c6e77
--- /dev/null
+++ b/elf/tst-dlopen-recurse.c
@@ -0,0 +1,34 @@
+/* Test that recursive dlopen runs constructors before return (bug 31986).
+ Copyright (C) 2024 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 <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+ void *handle = xdlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
+ int *status = dlsym (handle, "recursemod1_status");
+ printf ("info: recursemod1_status == %d (from main)\n", *status);
+ TEST_COMPARE (*status, 2);
+ xdlclose (handle);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlopen-recursemod1.c b/elf/tst-dlopen-recursemod1.c
new file mode 100644
index 0000000000000000..5e0cc0eb8c32d6d4
--- /dev/null
+++ b/elf/tst-dlopen-recursemod1.c
@@ -0,0 +1,50 @@
+/* Directly opened test module that gets recursively opened again.
+ Copyright (C) 2024 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 <stdio.h>
+#include <stdlib.h>
+#include <support/xdlfcn.h>
+
+int recursemod1_status;
+
+/* Force linking against st-dlopen-recursemod2.so. Also allows
+ checking for relocation. */
+extern int recursemod2_status;
+int *force_recursemod2_reference = &recursemod2_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ ++recursemod1_status;
+ printf ("info: tst-dlopen-recursemod1.so constructor called (status %d)\n",
+ recursemod1_status);
+}
+
+static void __attribute__ ((destructor))
+fini (void)
+{
+ /* The recursemod1_status variable was incremented in the
+ tst-dlopen-recursemod2.so constructor. */
+ printf ("info: tst-dlopen-recursemod1.so destructor called (status %d)\n",
+ recursemod1_status);
+ if (recursemod1_status != 2)
+ {
+ puts ("error: recursemod1_status == 2 expected");
+ exit (1);
+ }
+}
diff --git a/elf/tst-dlopen-recursemod2.c b/elf/tst-dlopen-recursemod2.c
new file mode 100644
index 0000000000000000..edd2f2526b877810
--- /dev/null
+++ b/elf/tst-dlopen-recursemod2.c
@@ -0,0 +1,66 @@
+/* Indirectly opened module that recursively opens the directly opened module.
+ Copyright (C) 2024 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 <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int recursemod2_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ ++recursemod2_status;
+ printf ("info: tst-dlopen-recursemod2.so constructor called (status %d)\n",
+ recursemod2_status);
+ void *handle = dlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
+ if (handle == NULL)
+ {
+ printf ("error: dlopen: %s\n", dlerror ());
+ exit (1);
+ }
+ int *status = dlsym (handle, "recursemod1_status");
+ if (status == NULL)
+ {
+ printf ("error: dlsym: %s\n", dlerror ());
+ exit (1);
+ }
+ printf ("info: recursemod1_status == %d\n", *status);
+ if (*status != 1)
+ {
+ puts ("error: recursemod1_status == 1 expected");
+ exit (1);
+ }
+ ++*status;
+ printf ("info: recursemod1_status == %d\n", *status);
+
+ int **mod2_status = dlsym (handle, "force_recursemod2_reference");
+ if (mod2_status == NULL || *mod2_status != &recursemod2_status)
+ {
+ puts ("error: invalid recursemod2_status address in"
+ " tst-dlopen-recursemod1.so");
+ exit (1);
+ }
+}
+
+static void __attribute__ ((destructor))
+fini (void)
+{
+ printf ("info: tst-dlopen-recursemod2.so destructor called (status %d)\n",
+ recursemod2_status);
+}

View File

@ -0,0 +1,97 @@
commit d6cc325fcf3d5a4ceeabfee465e6f90be1f72e8b
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Oct 25 16:50:10 2024 +0200
elf: Signal LA_ACT_CONSISTENT to auditors after RT_CONSISTENT switch
Auditors can call into the dynamic loader again if
LA_ACT_CONSISTENT, and those recursive calls could observe
r_state != RT_CONSISTENT.
We should consider failing dlopen/dlmopen/dlclose if
r_state != RT_CONSISTENT. The dynamic linker is probably not
in a state in which it can handle reentrant calls. This
needs further investigation.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit e096b7a1896886eb7dd2732ccbf1184b0eec9a63)
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 88226245eb4b7a81..b6f4daac792b8a90 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -723,6 +723,11 @@ _dl_close_worker (struct link_map *map, bool force)
/* TLS is cleaned up for the unloaded modules. */
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+ /* Notify the debugger those objects are finalized and gone. */
+ r->r_state = RT_CONSISTENT;
+ _dl_debug_state ();
+ LIBC_PROBE (unmap_complete, 2, nsid, r);
+
#ifdef SHARED
/* Auditing checkpoint: we have deleted all objects. Also, do not notify
auditors of the cleanup of a failed audit module loading attempt. */
@@ -735,11 +740,6 @@ _dl_close_worker (struct link_map *map, bool force)
--GL(dl_nns);
while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
- /* Notify the debugger those objects are finalized and gone. */
- r->r_state = RT_CONSISTENT;
- _dl_debug_state ();
- LIBC_PROBE (unmap_complete, 2, nsid, r);
-
/* Recheck if we need to retry, release the lock. */
out:
if (dl_close_state == rerun)
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 5139d276e04a5d85..5a30a57ee1487b31 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -639,17 +639,17 @@ dl_open_worker_begin (void *a)
#endif
}
-#ifdef SHARED
- /* Auditing checkpoint: we have added all objects. */
- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
-#endif
-
/* Notify the debugger all new objects are now ready to go. */
struct r_debug *r = _dl_debug_update (args->nsid);
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
+#ifdef SHARED
+ /* Auditing checkpoint: we have added all objects. */
+ _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
+#endif
+
_dl_open_check (new);
/* Print scope information. */
diff --git a/elf/rtld.c b/elf/rtld.c
index 4760633866cf9159..b308f7c9577b4bb3 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2416,9 +2416,6 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */
_dl_sysdep_start_cleanup ();
- /* Auditing checkpoint: we have added all objects. */
- _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
-
/* Notify the debugger all new objects are now ready to go. We must re-get
the address since by now the variable might be in another object. */
r = _dl_debug_update (LM_ID_BASE);
@@ -2426,6 +2423,9 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_debug_state ();
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
+ /* Auditing checkpoint: we have added all objects. */
+ _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
+
#if defined USE_LDCONFIG && !defined MAP_COPY
/* We must munmap() the cache file. */
_dl_unload_cache ();

View File

@ -0,0 +1,337 @@
commit 5f225025db0f5df9912893d4b399d9e640b84814
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Oct 25 16:50:10 2024 +0200
elf: Signal RT_CONSISTENT after relocation processing in dlopen (bug 31986)
Previously, a la_activity audit event was generated before
relocation processing completed. This does did not match what
happened during initial startup in elf/rtld.c (towards the end
of dl_main). It also caused various problems if an auditor
tried to open the same shared object again using dlmopen:
If it was the directly loaded object, it had a search scope
associated with it, so the early exit in dl_open_worker_begin
was taken even though the object was unrelocated. This caused
the r_state == RT_CONSISTENT assert to fail. Avoidance of the
assert also depends on reversing the order of r_state update
and auditor event (already implemented in a previous commit).
At the later point, args->map can be NULL due to failure,
so use the assigned namespace ID instead if that is available.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 43db5e2c0672cae7edea7c9685b22317eae25471)
diff --git a/elf/Makefile b/elf/Makefile
index 7690ee9edc0b0c9a..0f1125cb634d7184 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -414,6 +414,7 @@ tests += \
tst-dlmopen1 \
tst-dlmopen3 \
tst-dlmopen4 \
+ tst-dlopen-auditdup \
tst-dlopen-recurse \
tst-dlopen-self \
tst-dlopen-tlsmodid \
@@ -859,6 +860,8 @@ modules-names += \
tst-dlmopen-twice-mod1 \
tst-dlmopen-twice-mod2 \
tst-dlmopen1mod \
+ tst-dlopen-auditdup-auditmod \
+ tst-dlopen-auditdupmod \
tst-dlopen-recursemod1 \
tst-dlopen-recursemod2 \
tst-dlopen-sgid-mod \
@@ -3151,3 +3154,6 @@ $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
+tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
+$(objpfx)tst-dlopen-auditdup.out: \
+ $(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 5a30a57ee1487b31..88e8ad8d3abcdd44 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -576,6 +576,14 @@ dl_open_worker_begin (void *a)
_dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
new->l_name, new->l_ns, new->l_direct_opencount);
+#ifdef SHARED
+ /* No relocation processing on this execution path. But
+ relocation has not been performed for static
+ position-dependent executables, so disable the assert for
+ static linking. */
+ assert (new->l_relocated);
+#endif
+
/* If the user requested the object to be in the global
namespace but it is not so far, prepare to add it now. This
can raise an exception to do a malloc failure. */
@@ -597,10 +605,6 @@ dl_open_worker_begin (void *a)
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
add_to_global_update (new);
- const int r_state __attribute__ ((unused))
- = _dl_debug_update (args->nsid)->r_state;
- assert (r_state == RT_CONSISTENT);
-
/* Do not return without calling the (supposedly new) map's
constructor. This case occurs if a dependency of a directly
opened map has a constructor that calls dlopen again on the
@@ -639,17 +643,6 @@ dl_open_worker_begin (void *a)
#endif
}
- /* Notify the debugger all new objects are now ready to go. */
- struct r_debug *r = _dl_debug_update (args->nsid);
- r->r_state = RT_CONSISTENT;
- _dl_debug_state ();
- LIBC_PROBE (map_complete, 3, args->nsid, r, new);
-
-#ifdef SHARED
- /* Auditing checkpoint: we have added all objects. */
- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
-#endif
-
_dl_open_check (new);
/* Print scope information. */
@@ -696,6 +689,7 @@ dl_open_worker_begin (void *a)
created dlmopen namespaces. Do not do this for static dlopen
because libc has relocations against ld.so, which may not have
been relocated at this point. */
+ struct r_debug *r = _dl_debug_update (args->nsid);
#ifdef SHARED
if (GL(dl_ns)[args->nsid].libc_map != NULL)
_dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map,
@@ -787,6 +781,26 @@ dl_open_worker (void *a)
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+ /* Auditing checkpoint and debugger signalling. Do this even on
+ error, so that dlopen exists with consistent state. */
+ if (args->nsid >= 0 || args->map != NULL)
+ {
+ Lmid_t nsid = args->map != NULL ? args->map->l_ns : args->nsid;
+ struct r_debug *r = _dl_debug_update (nsid);
+#ifdef SHARED
+ bool was_not_consistent = r->r_state != RT_CONSISTENT;
+#endif
+ r->r_state = RT_CONSISTENT;
+ _dl_debug_state ();
+ LIBC_PROBE (map_complete, 3, nsid, r, new);
+
+#ifdef SHARED
+ if (was_not_consistent)
+ /* Avoid redudant/recursive signalling. */
+ _dl_audit_activity_nsid (nsid, LA_ACT_CONSISTENT);
+#endif
+ }
+
if (__glibc_unlikely (ex.errstring != NULL))
/* Reraise the error. */
_dl_signal_exception (err, &ex, NULL);
diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c
new file mode 100644
index 0000000000000000..9b67295e94d03e7a
--- /dev/null
+++ b/elf/tst-dlopen-auditdup-auditmod.c
@@ -0,0 +1,100 @@
+/* Auditor that opens again an object that just has been opened.
+ Copyright (C) 2024 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 <dlfcn.h>
+#include <link.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+unsigned int
+la_version (unsigned int v)
+{
+ return LAV_CURRENT;
+}
+
+static bool trigger_on_la_activity;
+
+unsigned int
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
+{
+ printf ("info: la_objopen: \"%s\"\n", map->l_name);
+ if (strstr (map->l_name, "/tst-dlopen-auditdupmod.so") != NULL)
+ trigger_on_la_activity = true;
+ return 0;
+}
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+ static unsigned int calls;
+ ++calls;
+ printf ("info: la_activity: call %u (flag %u)\n", calls, flag);
+ fflush (stdout);
+ if (trigger_on_la_activity)
+ {
+ /* Avoid triggering on the dlmopen call below. */
+ static bool recursion;
+ if (recursion)
+ return;
+ recursion = true;
+
+ puts ("info: about to dlmopen tst-dlopen-auditdupmod.so");
+ fflush (stdout);
+ void *handle = dlmopen (LM_ID_BASE, "tst-dlopen-auditdupmod.so",
+ RTLD_NOW);
+ if (handle == NULL)
+ {
+ printf ("error: dlmopen: %s\n", dlerror ());
+ fflush (stdout);
+ _exit (1);
+ }
+
+ /* Check that the constructor has run. */
+ int *status = dlsym (handle, "auditdupmod_status");
+ if (status == NULL)
+ {
+ printf ("error: dlsym: %s\n", dlerror ());
+ fflush (stdout);
+ _exit (1);
+ }
+ printf ("info: auditdupmod_status == %d\n", *status);
+ if (*status != 1)
+ {
+ puts ("error: auditdupmod_status == 1 expected");
+ fflush (stdout);
+ _exit (1);
+ }
+ /* Checked in the destructor and the main program. */
+ ++*status;
+ printf ("info: auditdupmod_status == %d\n", *status);
+
+ /* Check that the module has been relocated. */
+ int **status_address = dlsym (handle, "auditdupmod_status_address");
+ if (status_address == NULL || *status_address != status)
+ {
+ puts ("error: invalid auditdupmod_status address in"
+ " tst-dlopen-auditdupmod.so");
+ fflush (stdout);
+ _exit (1);
+ }
+
+ fflush (stdout);
+ }
+}
diff --git a/elf/tst-dlopen-auditdup.c b/elf/tst-dlopen-auditdup.c
new file mode 100644
index 0000000000000000..d022c58ae3091da1
--- /dev/null
+++ b/elf/tst-dlopen-auditdup.c
@@ -0,0 +1,36 @@
+/* Test that recursive dlopen from auditor works (bug 31986).
+ Copyright (C) 2024 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 <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+ puts ("info: about to dlopen tst-dlopen-auditdupmod.so");
+ fflush (stdout);
+ void *handle = xdlopen ("tst-dlopen-auditdupmod.so", RTLD_NOW);
+ int *status = xdlsym (handle, "auditdupmod_status");
+ printf ("info: auditdupmod_status == %d (from main)\n", *status);
+ TEST_COMPARE (*status, 2);
+ xdlclose (handle);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlopen-auditdupmod.c b/elf/tst-dlopen-auditdupmod.c
new file mode 100644
index 0000000000000000..59b7e21daa8212df
--- /dev/null
+++ b/elf/tst-dlopen-auditdupmod.c
@@ -0,0 +1,48 @@
+/* Directly opened test module that gets reopened from the auditor.
+ Copyright (C) 2024 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 <stdio.h>
+#include <stdlib.h>
+#include <support/xdlfcn.h>
+
+int auditdupmod_status;
+
+/* Used to check for successful relocation processing. */
+int *auditdupmod_status_address = &auditdupmod_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ ++auditdupmod_status;
+ printf ("info: tst-dlopen-auditdupmod.so constructor called (status %d)\n",
+ auditdupmod_status);
+}
+
+static void __attribute__ ((destructor))
+fini (void)
+{
+ /* The tst-dlopen-auditdup-auditmod.so auditor incremented
+ auditdupmod_status. */
+ printf ("info: tst-dlopen-auditdupmod.so destructor called (status %d)\n",
+ auditdupmod_status);
+ if (auditdupmod_status != 2)
+ {
+ puts ("error: auditdupmod_status == 2 expected");
+ exit (1);
+ }
+}

View File

@ -0,0 +1,26 @@
commit 46e3ecad27f65dd239d6d3568b81338f4525585f
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Oct 25 17:41:53 2024 +0200
elf: Fix map_complete Systemtap probe in dl_open_worker
The refactoring did not take the change of variable into account.
Fixes commit 43db5e2c0672cae7edea7c9685b22317eae25471
("elf: Signal RT_CONSISTENT after relocation processing in dlopen
(bug 31986)").
(cherry picked from commit ac73067cb7a328bf106ecd041c020fc61be7e087)
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 88e8ad8d3abcdd44..bd15f5f6a446115d 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -792,7 +792,7 @@ dl_open_worker (void *a)
#endif
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
- LIBC_PROBE (map_complete, 3, nsid, r, new);
+ LIBC_PROBE (map_complete, 3, nsid, r, args->map);
#ifdef SHARED
if (was_not_consistent)

View File

@ -0,0 +1,271 @@
commit 2b89de7c91e5e71732a32efef94075d9edbff95e
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Oct 28 14:45:30 2024 +0100
Revert "elf: Run constructors on cyclic recursive dlopen (bug 31986)"
This reverts commit 9897ced8e78db5d813166a7ccccfd5a42c69ef20.
Adjust the test expectations in elf/tst-dlopen-auditdup-auditmod.c
accordingly.
(cherry picked from commit 95129e6b8fabdaa8cd8a4a5cc20be0f4cb0ba59f)
diff --git a/elf/Makefile b/elf/Makefile
index 0f1125cb634d7184..479ef766c8f955f2 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -415,7 +415,6 @@ tests += \
tst-dlmopen3 \
tst-dlmopen4 \
tst-dlopen-auditdup \
- tst-dlopen-recurse \
tst-dlopen-self \
tst-dlopen-tlsmodid \
tst-dlopen-tlsreinit1 \
@@ -862,8 +861,6 @@ modules-names += \
tst-dlmopen1mod \
tst-dlopen-auditdup-auditmod \
tst-dlopen-auditdupmod \
- tst-dlopen-recursemod1 \
- tst-dlopen-recursemod2 \
tst-dlopen-sgid-mod \
tst-dlopen-tlsreinitmod1 \
tst-dlopen-tlsreinitmod2 \
@@ -3152,8 +3149,6 @@ tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
-$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
-$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
$(objpfx)tst-dlopen-auditdup.out: \
$(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
diff --git a/elf/dl-open.c b/elf/dl-open.c
index bd15f5f6a446115d..b00f283c42d19adb 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -605,14 +605,6 @@ dl_open_worker_begin (void *a)
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
add_to_global_update (new);
- /* Do not return without calling the (supposedly new) map's
- constructor. This case occurs if a dependency of a directly
- opened map has a constructor that calls dlopen again on the
- initially opened map. The new map is initialized last, so
- checking only it is enough. */
- if (!new->l_init_called)
- _dl_catch_exception (NULL, call_dl_init, args);
-
return;
}
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 94e8197c632c11c8..451932dd03e971b8 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -99,7 +99,6 @@ static struct link_map _dl_main_map =
.l_used = 1,
.l_tls_offset = NO_TLS_OFFSET,
.l_serial = 1,
- .l_init_called = 1,
};
/* Namespace information. */
diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c
index 9b67295e94d03e7a..270a595ec4de1439 100644
--- a/elf/tst-dlopen-auditdup-auditmod.c
+++ b/elf/tst-dlopen-auditdup-auditmod.c
@@ -66,7 +66,11 @@ la_activity (uintptr_t *cookie, unsigned int flag)
_exit (1);
}
- /* Check that the constructor has run. */
+ /* Check that the constructor has not run. Running the
+ constructor would require constructing its dependencies, but
+ the constructor call that triggered this auditing activity
+ has not completed, and constructors among the dependencies
+ may not be able to deal with that. */
int *status = dlsym (handle, "auditdupmod_status");
if (status == NULL)
{
@@ -75,9 +79,9 @@ la_activity (uintptr_t *cookie, unsigned int flag)
_exit (1);
}
printf ("info: auditdupmod_status == %d\n", *status);
- if (*status != 1)
+ if (*status != 0)
{
- puts ("error: auditdupmod_status == 1 expected");
+ puts ("error: auditdupmod_status == 0 expected");
fflush (stdout);
_exit (1);
}
diff --git a/elf/tst-dlopen-recurse.c b/elf/tst-dlopen-recurse.c
deleted file mode 100644
index c7fb379d373c6e77..0000000000000000
--- a/elf/tst-dlopen-recurse.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Test that recursive dlopen runs constructors before return (bug 31986).
- Copyright (C) 2024 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 <stdio.h>
-#include <support/check.h>
-#include <support/xdlfcn.h>
-
-static int
-do_test (void)
-{
- void *handle = xdlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
- int *status = dlsym (handle, "recursemod1_status");
- printf ("info: recursemod1_status == %d (from main)\n", *status);
- TEST_COMPARE (*status, 2);
- xdlclose (handle);
- return 0;
-}
-
-#include <support/test-driver.c>
diff --git a/elf/tst-dlopen-recursemod1.c b/elf/tst-dlopen-recursemod1.c
deleted file mode 100644
index 5e0cc0eb8c32d6d4..0000000000000000
--- a/elf/tst-dlopen-recursemod1.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Directly opened test module that gets recursively opened again.
- Copyright (C) 2024 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 <stdio.h>
-#include <stdlib.h>
-#include <support/xdlfcn.h>
-
-int recursemod1_status;
-
-/* Force linking against st-dlopen-recursemod2.so. Also allows
- checking for relocation. */
-extern int recursemod2_status;
-int *force_recursemod2_reference = &recursemod2_status;
-
-static void __attribute__ ((constructor))
-init (void)
-{
- ++recursemod1_status;
- printf ("info: tst-dlopen-recursemod1.so constructor called (status %d)\n",
- recursemod1_status);
-}
-
-static void __attribute__ ((destructor))
-fini (void)
-{
- /* The recursemod1_status variable was incremented in the
- tst-dlopen-recursemod2.so constructor. */
- printf ("info: tst-dlopen-recursemod1.so destructor called (status %d)\n",
- recursemod1_status);
- if (recursemod1_status != 2)
- {
- puts ("error: recursemod1_status == 2 expected");
- exit (1);
- }
-}
diff --git a/elf/tst-dlopen-recursemod2.c b/elf/tst-dlopen-recursemod2.c
deleted file mode 100644
index edd2f2526b877810..0000000000000000
--- a/elf/tst-dlopen-recursemod2.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Indirectly opened module that recursively opens the directly opened module.
- Copyright (C) 2024 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 <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int recursemod2_status;
-
-static void __attribute__ ((constructor))
-init (void)
-{
- ++recursemod2_status;
- printf ("info: tst-dlopen-recursemod2.so constructor called (status %d)\n",
- recursemod2_status);
- void *handle = dlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
- if (handle == NULL)
- {
- printf ("error: dlopen: %s\n", dlerror ());
- exit (1);
- }
- int *status = dlsym (handle, "recursemod1_status");
- if (status == NULL)
- {
- printf ("error: dlsym: %s\n", dlerror ());
- exit (1);
- }
- printf ("info: recursemod1_status == %d\n", *status);
- if (*status != 1)
- {
- puts ("error: recursemod1_status == 1 expected");
- exit (1);
- }
- ++*status;
- printf ("info: recursemod1_status == %d\n", *status);
-
- int **mod2_status = dlsym (handle, "force_recursemod2_reference");
- if (mod2_status == NULL || *mod2_status != &recursemod2_status)
- {
- puts ("error: invalid recursemod2_status address in"
- " tst-dlopen-recursemod1.so");
- exit (1);
- }
-}
-
-static void __attribute__ ((destructor))
-fini (void)
-{
- printf ("info: tst-dlopen-recursemod2.so destructor called (status %d)\n",
- recursemod2_status);
-}

View File

@ -0,0 +1,147 @@
commit b2d8c6cbe70bbafb2238f0595c36fbedf64d00c2
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 6 10:33:44 2024 +0100
elf: rtld_multiple_ref is always true
For a long time, libc.so.6 has dependend on ld.so, which
means that there is a reference to ld.so in all processes,
and rtld_multiple_ref is always true. In fact, if
rtld_multiple_ref were false, some of the ld.so setup code
would not run.
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f)
diff --git a/elf/rtld.c b/elf/rtld.c
index b308f7c9577b4bb3..41f8c329772b2b7a 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2010,43 +2010,37 @@ dl_main (const ElfW(Phdr) *phdr,
if (main_map->l_searchlist.r_list[i] == &GL(dl_rtld_map))
break;
- bool rtld_multiple_ref = false;
- if (__glibc_likely (i < main_map->l_searchlist.r_nlist))
- {
- /* Some DT_NEEDED entry referred to the interpreter object itself, so
- put it back in the list of visible objects. We insert it into the
- chain in symbol search order because gdb uses the chain's order as
- its symbol search order. */
- rtld_multiple_ref = true;
+ /* Insert the link map for the dynamic loader into the chain in
+ symbol search order because gdb uses the chain's order as its
+ symbol search order. */
- GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
- if (__glibc_likely (state.mode == rtld_mode_normal))
- {
- GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
- ? main_map->l_searchlist.r_list[i + 1]
- : NULL);
+ GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
+ if (__glibc_likely (state.mode == rtld_mode_normal))
+ {
+ GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
+ ? main_map->l_searchlist.r_list[i + 1]
+ : NULL);
#ifdef NEED_DL_SYSINFO_DSO
- if (GLRO(dl_sysinfo_map) != NULL
- && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
- && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
- GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
+ if (GLRO(dl_sysinfo_map) != NULL
+ && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
+ && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
+ GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
#endif
- }
- else
- /* In trace mode there might be an invisible object (which we
- could not find) after the previous one in the search list.
- In this case it doesn't matter much where we put the
- interpreter object, so we just initialize the list pointer so
- that the assertion below holds. */
- GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
-
- assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
- GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
- if (GL(dl_rtld_map).l_next != NULL)
- {
- assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
- GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
- }
+ }
+ else
+ /* In trace mode there might be an invisible object (which we
+ could not find) after the previous one in the search list.
+ In this case it doesn't matter much where we put the
+ interpreter object, so we just initialize the list pointer so
+ that the assertion below holds. */
+ GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
+
+ assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
+ GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
+ if (GL(dl_rtld_map).l_next != NULL)
+ {
+ assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
+ GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
}
/* Now let us see whether all libraries are available in the
@@ -2374,35 +2368,33 @@ dl_main (const ElfW(Phdr) *phdr,
/* Make sure no new search directories have been added. */
assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
- if (rtld_multiple_ref)
- {
- /* There was an explicit ref to the dynamic linker as a shared lib.
- Re-relocate ourselves with user-controlled symbol definitions.
+ /* Re-relocate ourselves with user-controlled symbol definitions.
- We must do this after TLS initialization in case after this
- re-relocation, we might call a user-supplied function
- (e.g. calloc from _dl_relocate_object) that uses TLS data. */
+ We must do this after TLS initialization in case after this
+ re-relocation, we might call a user-supplied function
+ (e.g. calloc from _dl_relocate_object) that uses TLS data. */
- /* Set up the object lookup structures. */
- _dl_find_object_init ();
+ /* Set up the object lookup structures. */
+ _dl_find_object_init ();
- /* The malloc implementation has been relocated, so resolving
- its symbols (and potentially calling IFUNC resolvers) is safe
- at this point. */
- __rtld_malloc_init_real (main_map);
+ /* The malloc implementation has been relocated, so resolving
+ its symbols (and potentially calling IFUNC resolvers) is safe
+ at this point. */
+ __rtld_malloc_init_real (main_map);
- /* Likewise for the locking implementation. */
- __rtld_mutex_init ();
+ /* Likewise for the locking implementation. */
+ __rtld_mutex_init ();
- RTLD_TIMING_VAR (start);
- rtld_timer_start (&start);
+ {
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
- /* Mark the link map as not yet relocated again. */
- GL(dl_rtld_map).l_relocated = 0;
- _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ /* Mark the link map as not yet relocated again. */
+ GL(dl_rtld_map).l_relocated = 0;
+ _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
- rtld_timer_accum (&relocate_time, start);
- }
+ rtld_timer_accum (&relocate_time, start);
+ }
/* Relocation is complete. Perform early libc initialization. This
is the initial libc, even if audit modules have been loaded with

View File

@ -0,0 +1,53 @@
commit 5434cc2c4152dddcfb2a6f6cb39b6ff33099a193
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 6 10:33:44 2024 +0100
elf: Do not define consider_profiling, consider_symbind as macros
This avoids surprises when refactoring the code if these identifiers
are re-used later in the file.
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit a79642204537dec8a1e1c58d1e0a074b3c624f46)
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 4bf7aec88b844bc7..b2c1627ceb847486 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -220,8 +220,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
int lazy = reloc_mode & RTLD_LAZY;
int skip_ifunc = reloc_mode & __RTLD_NOIFUNC;
-#ifdef SHARED
bool consider_symbind = false;
+#ifdef SHARED
/* If we are auditing, install the same handlers we need for profiling. */
if ((reloc_mode & __RTLD_AUDIT) == 0)
{
@@ -240,9 +240,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
}
#elif defined PROF
/* Never use dynamic linker profiling for gprof profiling code. */
-# define consider_profiling 0
-#else
-# define consider_symbind 0
+ consider_profiling = 0;
#endif
/* If DT_BIND_NOW is set relocate all references in this object. We
@@ -300,7 +298,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc);
-#ifndef PROF
if ((consider_profiling || consider_symbind)
&& l->l_info[DT_PLTRELSZ] != NULL)
{
@@ -321,7 +318,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
_dl_fatal_printf (errstring, RTLD_PROGNAME, l->l_name);
}
}
-#endif
}
/* Mark the object so we know this work has been done. */

View File

@ -0,0 +1,78 @@
commit 65d86471cee80144aee1829b191cd23dd9683497
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 6 10:33:44 2024 +0100
elf: Introduce _dl_relocate_object_no_relro
And make _dl_protect_relro apply RELRO conditionally.
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit f2326c2ec0a0a8db7bc7f4db8cce3002768fc3b6)
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index b2c1627ceb847486..76d14830ddda83b7 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -202,12 +202,9 @@ resolve_map (lookup_t l, struct r_scope_elem *scope[], const ElfW(Sym) **ref,
#include "dynamic-link.h"
void
-_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
- int reloc_mode, int consider_profiling)
+_dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
+ int reloc_mode, int consider_profiling)
{
- if (l->l_relocated)
- return;
-
struct textrels
{
caddr_t start;
@@ -338,17 +335,24 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
textrels = textrels->next;
}
-
- /* In case we can protect the data now that the relocations are
- done, do it. */
- if (l->l_relro_size != 0)
- _dl_protect_relro (l);
}
+void
+_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ int reloc_mode, int consider_profiling)
+{
+ if (l->l_relocated)
+ return;
+ _dl_relocate_object_no_relro (l, scope, reloc_mode, consider_profiling);
+ _dl_protect_relro (l);
+}
void
_dl_protect_relro (struct link_map *l)
{
+ if (l->l_relro_size == 0)
+ return;
+
ElfW(Addr) start = ALIGN_DOWN((l->l_addr
+ l->l_relro_addr),
GLRO(dl_pagesize));
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 259ce2e7d6e8ff31..91447a5e77c2466d 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1014,6 +1014,13 @@ extern void _dl_relocate_object (struct link_map *map,
int reloc_mode, int consider_profiling)
attribute_hidden;
+/* Perform relocation, but do not apply RELRO. Does not check
+ L->relocated. Otherwise the same as _dl_relocate_object. */
+void _dl_relocate_object_no_relro (struct link_map *map,
+ struct r_scope_elem *scope[],
+ int reloc_mode, int consider_profiling)
+ attribute_hidden;
+
/* Protect PT_GNU_RELRO area. */
extern void _dl_protect_relro (struct link_map *map) attribute_hidden;

View File

@ -0,0 +1,204 @@
commit 4f145bb35d5aed0cb102ba2a7b05aec1cf980672
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 6 10:33:44 2024 +0100
elf: Switch to main malloc after final ld.so self-relocation
Before commit ee1ada1bdb8074de6e1bdc956ab19aef7b6a7872
("elf: Rework exception handling in the dynamic loader
[BZ #25486]"), the previous order called the main calloc
to allocate a shadow GOT/PLT array for auditing support.
This happened before libc.so.6 ELF constructors were run, so
a user malloc could run without libc.so.6 having been
initialized fully. One observable effect was that
environ was NULL at this point.
It does not seem to be possible at present to trigger such
an allocation, but it seems more robust to delay switching
to main malloc after ld.so self-relocation is complete.
The elf/tst-rtld-no-malloc-audit test case fails with a
2.34-era glibc that does not have this fix.
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit c1560f3f75c0e892b5522c16f91b4e303f677094)
diff --git a/elf/Makefile b/elf/Makefile
index 479ef766c8f955f2..91fd05c9c0e6084a 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -453,6 +453,9 @@ tests += \
tst-recursive-tls \
tst-relsort1 \
tst-ro-dynamic \
+ tst-rtld-no-malloc \
+ tst-rtld-no-malloc-audit \
+ tst-rtld-no-malloc-preload \
tst-rtld-run-static \
tst-single_threaded \
tst-single_threaded-pthread \
@@ -3152,3 +3155,9 @@ $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
$(objpfx)tst-dlopen-auditdup.out: \
$(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
+
+# Reuse an audit module which provides ample debug logging.
+tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
+# Any shared object should do.
+tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 451932dd03e971b8..ee590edf93824d9b 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -338,8 +338,7 @@ _dl_non_dynamic_init (void)
call_function_static_weak (_dl_find_object_init);
/* Setup relro on the binary itself. */
- if (_dl_main_map.l_relro_size != 0)
- _dl_protect_relro (&_dl_main_map);
+ _dl_protect_relro (&_dl_main_map);
}
#ifdef DL_SYSINFO_IMPLEMENTATION
diff --git a/elf/rtld.c b/elf/rtld.c
index 41f8c329772b2b7a..ff938186738e8a87 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2368,30 +2368,27 @@ dl_main (const ElfW(Phdr) *phdr,
/* Make sure no new search directories have been added. */
assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
- /* Re-relocate ourselves with user-controlled symbol definitions.
-
- We must do this after TLS initialization in case after this
- re-relocation, we might call a user-supplied function
- (e.g. calloc from _dl_relocate_object) that uses TLS data. */
-
/* Set up the object lookup structures. */
_dl_find_object_init ();
- /* The malloc implementation has been relocated, so resolving
- its symbols (and potentially calling IFUNC resolvers) is safe
- at this point. */
- __rtld_malloc_init_real (main_map);
-
/* Likewise for the locking implementation. */
__rtld_mutex_init ();
+ /* Re-relocate ourselves with user-controlled symbol definitions. */
+
{
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
- /* Mark the link map as not yet relocated again. */
- GL(dl_rtld_map).l_relocated = 0;
- _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+
+ /* The malloc implementation has been relocated, so resolving
+ its symbols (and potentially calling IFUNC resolvers) is safe
+ at this point. */
+ __rtld_malloc_init_real (main_map);
+
+ if (GL(dl_rtld_map).l_relro_size != 0)
+ _dl_protect_relro (&GL(dl_rtld_map));
rtld_timer_accum (&relocate_time, start);
}
diff --git a/elf/tst-rtld-no-malloc-audit.c b/elf/tst-rtld-no-malloc-audit.c
new file mode 100644
index 0000000000000000..a028377ad1fea027
--- /dev/null
+++ b/elf/tst-rtld-no-malloc-audit.c
@@ -0,0 +1 @@
+#include "tst-rtld-no-malloc.c"
diff --git a/elf/tst-rtld-no-malloc-preload.c b/elf/tst-rtld-no-malloc-preload.c
new file mode 100644
index 0000000000000000..a028377ad1fea027
--- /dev/null
+++ b/elf/tst-rtld-no-malloc-preload.c
@@ -0,0 +1 @@
+#include "tst-rtld-no-malloc.c"
diff --git a/elf/tst-rtld-no-malloc.c b/elf/tst-rtld-no-malloc.c
new file mode 100644
index 0000000000000000..5f24d4bd72c4af0c
--- /dev/null
+++ b/elf/tst-rtld-no-malloc.c
@@ -0,0 +1,76 @@
+/* Test that program loading does not call malloc.
+ Copyright (C) 2024 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 <string.h>
+#include <unistd.h>
+
+static void
+print (const char *s)
+{
+ const char *end = s + strlen (s);
+ while (s < end)
+ {
+ ssize_t ret = write (STDOUT_FILENO, s, end - s);
+ if (ret <= 0)
+ _exit (2);
+ s += ret;
+ }
+}
+
+static void __attribute__ ((noreturn))
+unexpected_call (const char *function)
+{
+ print ("error: unexpected call to ");
+ print (function);
+ print ("\n");
+ _exit (1);
+}
+
+/* These are the malloc functions implement in elf/dl-minimal.c. */
+
+void
+free (void *ignored)
+{
+ unexpected_call ("free");
+}
+
+void *
+calloc (size_t ignored1, size_t ignored2)
+{
+ unexpected_call ("calloc");
+}
+
+void *
+malloc (size_t ignored)
+{
+ unexpected_call ("malloc");
+}
+
+void *
+realloc (void *ignored1, size_t ignored2)
+{
+ unexpected_call ("realloc");
+}
+
+int
+main (void)
+{
+ /* Do not use the test wrapper, to avoid spurious malloc calls from it. */
+ return 0;
+}

View File

@ -0,0 +1,77 @@
commit d21a217fa0199fed74f975b498408abb7606f6fe
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Sep 3 17:52:47 2024 +0200
elf: Update DSO list, write audit log to elf/tst-audit23.out
After commit 1d5024f4f052c12e404d42d3b5bfe9c3e9fd27c4
("support: Build with exceptions and asynchronous unwind tables
[BZ #30587]"), libgcc_s is expected to show up in the DSO
list on 32-bit Arm. Do not update max_objs because vdso is not
tracked (and which is the reason why the test currently passes
even with libgcc_s present).
Also write the log output from the auditor to standard output,
for easier test debugging.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 4a50fdf8b2c1106b50cd9056b4c6f3a72cdeed5f)
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
index 32e7c8b2a3129c51..dada6bb1f8dabab5 100644
--- a/elf/tst-audit23.c
+++ b/elf/tst-audit23.c
@@ -85,13 +85,28 @@ do_test (int argc, char *argv[])
= support_capture_subprogram (spargv[0], spargv);
support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
+ {
+ FILE *fp = fmemopen (result.err.buffer, result.err.length, "r");
+ TEST_VERIFY (fp != NULL);
+ unsigned int line = 0;
+ char *buffer = NULL;
+ size_t buffer_length = 0;
+ puts ("info: *** audit log start ***");
+ while (xgetline (&buffer, &buffer_length, fp))
+ printf ("%6u\t%s", ++line, buffer);
+ puts ("info: *** audit log end ***");
+ free (buffer);
+ xfclose (fp);
+ }
+
/* The expected la_objopen/la_objclose:
1. executable
2. loader
3. libc.so
- 4. tst-audit23mod.so
- 5. libc.so (LM_ID_NEWLM).
- 6. vdso (optional and ignored). */
+ 4. libgcc_s.so (one some architectures, for libsupport)
+ 5. tst-audit23mod.so
+ 6. libc.so (LM_ID_NEWLM).
+ vdso (optional and ignored). */
enum { max_objs = 6 };
struct la_obj_t
{
@@ -115,8 +130,10 @@ do_test (int argc, char *argv[])
TEST_VERIFY (out != NULL);
char *buffer = NULL;
size_t buffer_length = 0;
+ unsigned int line = 0;
while (xgetline (&buffer, &buffer_length, out))
{
+ ++line;
if (startswith (buffer, "la_activity: "))
{
uintptr_t cookie;
@@ -174,8 +191,8 @@ do_test (int argc, char *argv[])
if (is_vdso (lname))
continue;
if (nobjs == max_objs)
- FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
- lname, laddr, lmid);
+ FAIL_EXIT1 ("(line %u) non expected la_objopen: %s %"PRIxPTR" %ld",
+ line, lname, laddr, lmid);
objs[nobjs].lname = lname;
objs[nobjs].laddr = laddr;
objs[nobjs].lmid = lmid;

View File

@ -0,0 +1,35 @@
commit fef226255dda886d74dc72c5e43dbdde231cc74e
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Nov 29 15:36:40 2024 +0100
elf: Add the endswith function to <endswith.h>
And include <stdbool.h> for a definition of bool.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit a20bc2f6233a726c7df8eaa332b6e498bd59321f)
diff --git a/elf/endswith.h b/elf/endswith.h
index c6430c48be0c1071..3954e57f8eff0faa 100644
--- a/elf/endswith.h
+++ b/elf/endswith.h
@@ -17,6 +17,7 @@
#ifndef _ENDSWITH_H
#define _ENDSWITH_H
+#include <stdbool.h>
#include <string.h>
/* Return true if the N bytes at NAME end with with the characters in
@@ -30,4 +31,11 @@ endswithn (const char *name, size_t n, const char *suffix)
strlen (suffix)) == 0);
}
+/* Same as endswithn, but uses the entire SUBJECT for matching. */
+static inline bool
+endswith (const char *subject, const char *suffix)
+{
+ return endswithn (subject, strlen (subject), suffix);
+}
+
#endif /* _ENDSWITH_H */

View File

@ -0,0 +1,132 @@
commit e27601b385fba1f3598168136021764166b819cf
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 9 15:31:18 2024 +0200
elf: Signal la_objopen for the proxy link map in dlmopen (bug 31985)
Previously, the ld.so link map was silently added to the namespace.
This change produces an auditing event for it.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 8f36b1469677afe37168f9af1b77402d7a70c673)
diff --git a/elf/dl-load.c b/elf/dl-load.c
index ce8fdea3024359b0..75a7187c649e0202 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -929,6 +929,37 @@ _dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph)
}
}
+static void
+_dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l)
+{
+ /* Signal that we are going to add new objects. */
+ struct r_debug *r = _dl_debug_update (nsid);
+ if (r->r_state == RT_CONSISTENT)
+ {
+#ifdef SHARED
+ /* Auditing checkpoint: we are going to add new objects. Since this
+ is called after _dl_add_to_namespace_list the namespace is guaranteed
+ to not be empty. */
+ if ((mode & __RTLD_AUDIT) == 0)
+ _dl_audit_activity_nsid (nsid, LA_ACT_ADD);
+#endif
+
+ /* Notify the debugger we have added some objects. We need to
+ call _dl_debug_initialize in a static program in case dynamic
+ linking has not been used before. */
+ r->r_state = RT_ADD;
+ _dl_debug_state ();
+ LIBC_PROBE (map_start, 2, nsid, r);
+ }
+ else
+ assert (r->r_state == RT_ADD);
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have a new object. */
+ if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
+ _dl_audit_objopen (l, nsid);
+#endif
+}
/* Map in the shared object NAME, actually located in REALNAME, and already
opened on FD. */
@@ -1029,6 +1060,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
/* Add the map for the mirrored object to the object list. */
_dl_add_to_namespace_list (l, nsid);
+ _dl_notify_new_object (mode, nsid, l);
+
return l;
}
#endif
@@ -1487,33 +1520,7 @@ cannot enable executable stack as shared object requires");
if (mode & __RTLD_SPROF)
return l;
- /* Signal that we are going to add new objects. */
- struct r_debug *r = _dl_debug_update (nsid);
- if (r->r_state == RT_CONSISTENT)
- {
-#ifdef SHARED
- /* Auditing checkpoint: we are going to add new objects. Since this
- is called after _dl_add_to_namespace_list the namespace is guaranteed
- to not be empty. */
- if ((mode & __RTLD_AUDIT) == 0)
- _dl_audit_activity_nsid (nsid, LA_ACT_ADD);
-#endif
-
- /* Notify the debugger we have added some objects. We need to
- call _dl_debug_initialize in a static program in case dynamic
- linking has not been used before. */
- r->r_state = RT_ADD;
- _dl_debug_state ();
- LIBC_PROBE (map_start, 2, nsid, r);
- }
- else
- assert (r->r_state == RT_ADD);
-
-#ifdef SHARED
- /* Auditing checkpoint: we have a new object. */
- if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
- _dl_audit_objopen (l, nsid);
-#endif
+ _dl_notify_new_object (mode, nsid, l);
return l;
}
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
index dada6bb1f8dabab5..32759f956a4b3c58 100644
--- a/elf/tst-audit23.c
+++ b/elf/tst-audit23.c
@@ -17,6 +17,7 @@
<https://www.gnu.org/licenses/>. */
#include <array_length.h>
+#include <endswith.h>
#include <errno.h>
#include <getopt.h>
#include <link.h>
@@ -106,8 +107,9 @@ do_test (int argc, char *argv[])
4. libgcc_s.so (one some architectures, for libsupport)
5. tst-audit23mod.so
6. libc.so (LM_ID_NEWLM).
+ 7. loader (proxy link map in new namespace)
vdso (optional and ignored). */
- enum { max_objs = 6 };
+ enum { max_objs = 7 };
struct la_obj_t
{
char *lname;
@@ -236,7 +238,9 @@ do_test (int argc, char *argv[])
for (size_t i = 0; i < nobjs; i++)
{
- TEST_COMPARE (objs[i].closed, true);
+ /* This subtest currently does not pass because of bug 32065. */
+ if (! (endswith (objs[i].lname, LD_SO) && objs[i].lmid != LM_ID_BASE))
+ TEST_COMPARE (objs[i].closed, true);
free (objs[i].lname);
}

View File

@ -0,0 +1,77 @@
commit f407a14ff7788cb6158d91d2cd9850f218e796d3
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 9 16:06:40 2024 +0200
elf: Call la_objclose for proxy link maps in _dl_fini (bug 32065)
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit c4b160744cb39eca20dc36b39c7fa6e10352706c)
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index db996270de65e86a..a1a4c25829471510 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -69,6 +69,7 @@ _dl_fini (void)
unsigned int i;
struct link_map *l;
+ struct link_map *proxy_link_map = NULL;
assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
/* Do not handle ld.so in secondary namespaces. */
@@ -84,6 +85,11 @@ _dl_fini (void)
are not dlclose()ed from underneath us. */
++l->l_direct_opencount;
}
+ else
+ /* Used below to call la_objclose for the ld.so proxy
+ link map. */
+ proxy_link_map = l;
+
assert (ns != LM_ID_BASE || i == nloaded);
assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
unsigned int nmaps = i;
@@ -122,6 +128,9 @@ _dl_fini (void)
--l->l_direct_opencount;
}
+ if (proxy_link_map != NULL)
+ _dl_audit_objclose (proxy_link_map);
+
#ifdef SHARED
_dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT);
#endif
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
index 32759f956a4b3c58..78b4ee384cfb0fe9 100644
--- a/elf/tst-audit23.c
+++ b/elf/tst-audit23.c
@@ -236,13 +236,26 @@ do_test (int argc, char *argv[])
}
}
+ Lmid_t lmid_other = LM_ID_NEWLM;
+ unsigned int other_namespace_count = 0;
for (size_t i = 0; i < nobjs; i++)
{
- /* This subtest currently does not pass because of bug 32065. */
- if (! (endswith (objs[i].lname, LD_SO) && objs[i].lmid != LM_ID_BASE))
- TEST_COMPARE (objs[i].closed, true);
+ if (objs[i].lmid != LM_ID_BASE)
+ {
+ if (lmid_other == LM_ID_NEWLM)
+ lmid_other = objs[i].lmid;
+ TEST_COMPARE (objs[i].lmid, lmid_other);
+ ++other_namespace_count;
+ if (!(endswith (objs[i].lname, "/" LIBC_SO)
+ || endswith (objs[i].lname, "/" LD_SO)))
+ FAIL ("unexpected object in secondary namespace: %s",
+ objs[i].lname);
+ }
+ TEST_COMPARE (objs[i].closed, true);
free (objs[i].lname);
}
+ /* Both libc.so and ld.so should be present. */
+ TEST_COMPARE (other_namespace_count, 2);
/* la_activity(LA_ACT_CONSISTENT) should be the last callback received.
Since only one link map may be not-CONSISTENT at a time, this also

View File

@ -0,0 +1,141 @@
commit 4c9b1877fde6535efb8bd3ba1888d1ef82c9a663
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Sep 3 17:57:46 2024 +0200
elf: Reorder audit events in dlcose to match _dl_fini (bug 32066)
This was discovered after extending elf/tst-audit23 to cover
dlclose of the dlmopen namespace.
Auditors already experience the new order during process
shutdown (_dl_fini), so no LAV_CURRENT bump or backwards
compatibility code seems necessary.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 495b96e064da605630a23092d1e484ade4bdc093)
diff --git a/elf/dl-close.c b/elf/dl-close.c
index b6f4daac792b8a90..4c963097f4dc8d79 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -264,6 +264,12 @@ _dl_close_worker (struct link_map *map, bool force)
_dl_catch_exception (NULL, _dl_call_fini, imap);
#ifdef SHARED
+ /* Auditing checkpoint: we will start deleting objects.
+ This is supposed to happen before la_objclose (see _dl_fini),
+ but only once per non-recursive dlclose call. */
+ if (!unload_any)
+ _dl_audit_activity_nsid (nsid, LA_ACT_DELETE);
+
/* Auditing checkpoint: we remove an object. */
_dl_audit_objclose (imap);
#endif
@@ -424,12 +430,8 @@ _dl_close_worker (struct link_map *map, bool force)
if (!unload_any)
goto out;
-#ifdef SHARED
- /* Auditing checkpoint: we will start deleting objects. */
- _dl_audit_activity_nsid (nsid, LA_ACT_DELETE);
-#endif
-
- /* Notify the debugger we are about to remove some loaded objects. */
+ /* Notify the debugger we are about to remove some loaded objects.
+ LA_ACT_DELETE has already been signalled above for !unload_any. */
struct r_debug *r = _dl_debug_update (nsid);
r->r_state = RT_DELETE;
_dl_debug_state ();
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
index 78b4ee384cfb0fe9..1b76336595fcd301 100644
--- a/elf/tst-audit23.c
+++ b/elf/tst-audit23.c
@@ -31,16 +31,21 @@
#include <support/xstdio.h>
#include <support/xdlfcn.h>
#include <support/support.h>
+#include <support/test-driver.h>
static int restart;
+static int do_dlclose;
#define CMDLINE_OPTIONS \
- { "restart", no_argument, &restart, 1 },
+ { "restart", no_argument, &restart, 1 }, \
+ { "dlclose", no_argument, &do_dlclose, 1 }, \
static int
handle_restart (void)
{
xdlopen ("tst-audit23mod.so", RTLD_NOW);
- xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
+ void *handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
+ if (do_dlclose)
+ xdlclose (handle);
return 0;
}
@@ -60,8 +65,8 @@ is_vdso (const char *str)
|| startswith (str, "linux-vdso");
}
-static int
-do_test (int argc, char *argv[])
+static void
+do_one_test (int argc, char *argv[], bool pass_dlclose_flag)
{
/* We must have either:
- One or four parameters left if called initially:
@@ -69,16 +74,15 @@ do_test (int argc, char *argv[])
+ "--library-path" optional
+ the library path optional
+ the application name */
- if (restart)
- return handle_restart ();
-
- char *spargv[9];
+ char *spargv[10];
TEST_VERIFY_EXIT (((argc - 1) + 3) < array_length (spargv));
int i = 0;
for (; i < argc - 1; i++)
spargv[i] = argv[i + 1];
spargv[i++] = (char *) "--direct";
spargv[i++] = (char *) "--restart";
+ if (pass_dlclose_flag)
+ spargv[i++] = (char *) "--dlclose";
spargv[i] = NULL;
setenv ("LD_AUDIT", "tst-auditmod23.so", 0);
@@ -146,8 +150,14 @@ do_test (int argc, char *argv[])
/* The cookie identifies the object at the head of the link map,
so we only add a new namespace if it changes from the previous
- one. This works since dlmopen is the last in the test body. */
- if (cookie != last_act_cookie && last_act_cookie != -1)
+ one. This works since dlmopen is the last in the test body.
+
+ Currently, this does not work as expected because there
+ is no head link map if a namespace is completely deleted.
+ No LA_ACT_CONSISTENT event is generated in that case.
+ See the comment in _dl_audit_activity_nsid and bug 32068. */
+ if (cookie != last_act_cookie && last_act_cookie != -1
+ && !pass_dlclose_flag)
TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
if (this_act == LA_ACT_ADD && acts[nacts] != cookie)
@@ -265,7 +275,16 @@ do_test (int argc, char *argv[])
free (buffer);
xfclose (out);
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+ if (restart)
+ return handle_restart ();
+ do_one_test (argc, argv, false);
+ do_one_test (argc, argv, true);
return 0;
}

View File

@ -0,0 +1,223 @@
commit 5f5c411132676d4c5eb171354c51b62baea27493
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Jan 7 09:18:07 2025 +0100
elf: Second ld.so relocation only if libc.so has been loaded
Commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf:
rtld_multiple_ref is always true”) removed some code that happened
to enable compatibility with programs that do not link against
libc.so. Such programs cannot call dlopen or any dynamic linker
functions (except __tls_get_addr), so this is not really useful.
Still ld.so should not crash with a null-pointer dereference
or undefined symbol reference in these cases.
In the main relocation loop, call _dl_relocate_object unconditionally
because it already checks if the object has been relocated.
If libc.so was loaded, self-relocate ld.so against it and call
__rtld_mutex_init and __rtld_malloc_init_real to activate the full
implementations. Those are available only if libc.so is there,
so skip these initialization steps if libc.so is absent. Without
libc.so, the global scope can be completely empty. This can cause
ld.so self-relocation to fail because if it uses symbol-based
relocations, which is why the second ld.so self-relocation is not
performed if libc.so is missing.
The previous concern regarding GOT updates through self-relocation
no longer applies because function pointers are updated
explicitly through __rtld_mutex_init and __rtld_malloc_init_real,
and not through relocation. However, the second ld.so self-relocation
is still delayed, in case there are other symbols being used.
Fixes commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf:
rtld_multiple_ref is always true”).
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 706209867f1ba89c458033408d419e92d8055f58)
diff --git a/elf/Makefile b/elf/Makefile
index 91fd05c9c0e6084a..59de78a5d45bced4 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -3161,3 +3161,20 @@ tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
# Any shared object should do.
tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
+
+# These rules link and run the special elf/tst-nolink-libc-* tests if
+# a port adds them to the tests variables. Neither test variant is
+# linked against libc.so, but tst-nolink-libc-1 is linked against
+# ld.so. The test is always run directly, not under the dynamic
+# linker.
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector)
+$(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
+ -Wl,--dynamic-linker=$(objpfx)ld.so,--no-as-needed $(objpfx)ld.so
+$(objpfx)tst-nolink-libc-1.out: $(objpfx)tst-nolink-libc-1 $(objpfx)ld.so
+ $< > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
+ -Wl,--dynamic-linker=$(objpfx)ld.so
+$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so
+ $< > $@ 2>&1; $(evaluate-test)
diff --git a/elf/rtld.c b/elf/rtld.c
index ff938186738e8a87..809fc807989b285e 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2290,25 +2290,25 @@ dl_main (const ElfW(Phdr) *phdr,
_rtld_main_check (main_map, _dl_argv[0]);
- /* Now we have all the objects loaded. Relocate them all except for
- the dynamic linker itself. We do this in reverse order so that copy
- relocs of earlier objects overwrite the data written by later
- objects. We do not re-relocate the dynamic linker itself in this
- loop because that could result in the GOT entries for functions we
- call being changed, and that would break us. It is safe to relocate
- the dynamic linker out of order because it has no copy relocations.
- Likewise for libc, which is relocated early to ensure that IFUNC
- resolvers in libc work. */
+ /* Now we have all the objects loaded. */
int consider_profiling = GLRO(dl_profile) != NULL;
/* If we are profiling we also must do lazy reloaction. */
GLRO(dl_lazy) |= consider_profiling;
+ /* If libc.so has been loaded, relocate it early, after the dynamic
+ loader itself. The initial self-relocation of ld.so should be
+ sufficient for IFUNC resolvers in libc.so. */
if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
- _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map,
- GL(dl_ns)[LM_ID_BASE].libc_map->l_scope,
- GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling);
+ {
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
+ _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map,
+ GL(dl_ns)[LM_ID_BASE].libc_map->l_scope,
+ GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling);
+ rtld_timer_accum (&relocate_time, start);
+ }
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
@@ -2331,9 +2331,8 @@ dl_main (const ElfW(Phdr) *phdr,
/* Also allocated with the fake malloc(). */
l->l_free_initfini = 0;
- if (l != &GL(dl_rtld_map))
- _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
- consider_profiling);
+ _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
+ consider_profiling);
/* Add object to slot information data if necessasy. */
if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called)
@@ -2371,27 +2370,22 @@ dl_main (const ElfW(Phdr) *phdr,
/* Set up the object lookup structures. */
_dl_find_object_init ();
- /* Likewise for the locking implementation. */
- __rtld_mutex_init ();
-
- /* Re-relocate ourselves with user-controlled symbol definitions. */
-
- {
- RTLD_TIMING_VAR (start);
- rtld_timer_start (&start);
-
- _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
-
- /* The malloc implementation has been relocated, so resolving
- its symbols (and potentially calling IFUNC resolvers) is safe
- at this point. */
- __rtld_malloc_init_real (main_map);
+ /* If libc.so was loaded, relocate ld.so against it. Complete ld.so
+ initialization with mutex symbols from libc.so and malloc symbols
+ from the global scope. */
+ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
+ {
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
+ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ rtld_timer_accum (&relocate_time, start);
- if (GL(dl_rtld_map).l_relro_size != 0)
- _dl_protect_relro (&GL(dl_rtld_map));
+ __rtld_mutex_init ();
+ __rtld_malloc_init_real (main_map);
+ }
- rtld_timer_accum (&relocate_time, start);
- }
+ /* All ld.so initialization is complete. Apply RELRO. */
+ _dl_protect_relro (&GL(dl_rtld_map));
/* Relocation is complete. Perform early libc initialization. This
is the initial libc, even if audit modules have been loaded with
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index b0daa44b95db3b72..a4b692febb3e87d9 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -657,7 +657,15 @@ install-bin += \
# install-bin
$(objpfx)pldd: $(objpfx)xmalloc.o
+
+test-internal-extras += tst-nolink-libc
+ifeq ($(run-built-tests),yes)
+tests-special += \
+ $(objpfx)tst-nolink-libc-1.out \
+ $(objpfx)tst-nolink-libc-2.out \
+ # tests-special
endif
+endif # $(subdir) == elf
ifeq ($(subdir),rt)
CFLAGS-mq_send.c += -fexceptions
diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile
index a73c897f43c9a206..e73ce4f81114e789 100644
--- a/sysdeps/unix/sysv/linux/arm/Makefile
+++ b/sysdeps/unix/sysv/linux/arm/Makefile
@@ -1,5 +1,8 @@
ifeq ($(subdir),elf)
sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
+# The test uses INTERNAL_SYSCALL_CALL. In thumb mode, this uses
+# an undefined reference to __libc_do_syscall.
+CFLAGS-tst-nolink-libc.c += -marm
endif
ifeq ($(subdir),misc)
diff --git a/sysdeps/unix/sysv/linux/tst-nolink-libc.c b/sysdeps/unix/sysv/linux/tst-nolink-libc.c
new file mode 100644
index 0000000000000000..817f37784b4080f9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-nolink-libc.c
@@ -0,0 +1,25 @@
+/* Test program not linked against libc.so and not using any glibc functions.
+ Copyright (C) 2024 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 <sysdep.h>
+
+void
+_start (void)
+{
+ INTERNAL_SYSCALL_CALL (exit_group, 0);
+}

View File

@ -0,0 +1,283 @@
commit 79d84b5da58ee989fdabf34767e1501a4b222194
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Mar 7 17:37:50 2025 +0100
elf: Fix handling of symbol versions which hash to zero (bug 29190)
This was found through code inspection. No application impact is
known.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 46d31980943d8be2f421c1e3276b265c7552636e)
diff --git a/elf/Makefile b/elf/Makefile
index 59de78a5d45bced4..10c54be629124a17 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -488,6 +488,7 @@ tests += \
tst-unique2 \
tst-unwind-ctor \
tst-unwind-main \
+ tst-version-hash-zero \
unload3 \
unload4 \
unload5 \
@@ -979,6 +980,9 @@ modules-names += \
tst-unique2mod1 \
tst-unique2mod2 \
tst-unwind-ctor-lib \
+ tst-version-hash-zero-linkmod \
+ tst-version-hash-zero-mod \
+ tst-version-hash-zero-refmod \
unload2dep \
unload2mod \
unload3mod1 \
@@ -3178,3 +3182,20 @@ $(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o
-Wl,--dynamic-linker=$(objpfx)ld.so
$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so
$< > $@ 2>&1; $(evaluate-test)
+
+$(objpfx)tst-version-hash-zero.out: \
+ $(objpfx)tst-version-hash-zero-mod.so \
+ $(objpfx)tst-version-hash-zero-refmod.so
+LDFLAGS-tst-version-hash-zero-mod.so = \
+ -Wl,--version-script=tst-version-hash-zero-mod.map
+# The run-time test module tst-version-hash-zero-refmod.so is linked
+# to a stub module, tst-version-hash-zero-linkmod.so, to produce an
+# expected relocation error.
+$(objpfx)tst-version-hash-zero-refmod.so: \
+ $(objpfx)tst-version-hash-zero-linkmod.so
+LDFLAGS-tst-version-hash-zero-linkmod.so = \
+ -Wl,--version-script=tst-version-hash-zero-linkmod.map \
+ -Wl,--soname=tst-version-hash-zero-mod.so
+$(objpfx)tst-version-hash-zero-refmod.so: \
+ $(objpfx)tst-version-hash-zero-linkmod.so
+tst-version-hash-zero-refmod.so-no-z-defs = yes
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 19ad2a25c5f70326..7a70f1df2d6cf839 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -113,12 +113,22 @@ check_match (const char *const undef_name,
/* We can match the version information or use the
default one if it is not hidden. */
ElfW(Half) ndx = verstab[symidx] & 0x7fff;
- if ((map->l_versions[ndx].hash != version->hash
- || strcmp (map->l_versions[ndx].name, version->name))
- && (version->hidden || map->l_versions[ndx].hash
- || (verstab[symidx] & 0x8000)))
- /* It's not the version we want. */
- return NULL;
+ if (map->l_versions[ndx].hash == version->hash
+ && strcmp (map->l_versions[ndx].name, version->name) == 0)
+ /* This is an exact version match. Return the symbol below. */
+ ;
+ else
+ {
+ if (!version->hidden
+ && map->l_versions[ndx].name[0] == '\0'
+ && (verstab[symidx] & 0x8000) == 0
+ && (*num_versions)++ == 0)
+ /* This is the global default version. Store it as a
+ fallback match. */
+ *versioned_sym = sym;
+
+ return NULL;
+ }
}
}
else
diff --git a/elf/dl-version.c b/elf/dl-version.c
index 8966d612cc79f0f1..708b1c94ea47d147 100644
--- a/elf/dl-version.c
+++ b/elf/dl-version.c
@@ -357,6 +357,13 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
}
}
+
+ /* The empty string has ELF hash zero. This avoids a NULL check
+ before the version string comparison in check_match in
+ dl-lookup.c. */
+ for (unsigned int i = 0; i < map->l_nversions; ++i)
+ if (map->l_versions[i].name == NULL)
+ map->l_versions[i].name = "";
}
/* When there is a DT_VERNEED entry with libc.so on DT_NEEDED, issue
diff --git a/elf/tst-version-hash-zero-linkmod.c b/elf/tst-version-hash-zero-linkmod.c
new file mode 100644
index 0000000000000000..15e2506d0111bc7e
--- /dev/null
+++ b/elf/tst-version-hash-zero-linkmod.c
@@ -0,0 +1,22 @@
+/* Stub module for linking tst-version-hash-zero-refmod.so.
+ 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; see the file COPYING.LIB. If
+ not, see <https://www.gnu.org/licenses/>. */
+
+/* The version script assigns a different symbol version for the stub
+ module. Loading the module with the incorrect version is expected
+ to fail. */
+#include "tst-version-hash-zero-mod.c"
diff --git a/elf/tst-version-hash-zero-linkmod.map b/elf/tst-version-hash-zero-linkmod.map
new file mode 100644
index 0000000000000000..2dba7c22d7ea7d09
--- /dev/null
+++ b/elf/tst-version-hash-zero-linkmod.map
@@ -0,0 +1,7 @@
+Base {
+ local: *;
+};
+
+OTHER_VERSION {
+ global: global_variable;
+} Base;
diff --git a/elf/tst-version-hash-zero-mod.c b/elf/tst-version-hash-zero-mod.c
new file mode 100644
index 0000000000000000..ac6b0dc4a57b5775
--- /dev/null
+++ b/elf/tst-version-hash-zero-mod.c
@@ -0,0 +1,20 @@
+/* Test module with a zero version symbol hash.
+ 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; see the file COPYING.LIB. If
+ not, see <https://www.gnu.org/licenses/>. */
+
+/* The symbol version is assigned by version script. */
+int global_variable;
diff --git a/elf/tst-version-hash-zero-mod.map b/elf/tst-version-hash-zero-mod.map
new file mode 100644
index 0000000000000000..41eaff79147a8fcd
--- /dev/null
+++ b/elf/tst-version-hash-zero-mod.map
@@ -0,0 +1,13 @@
+Base {
+ local: *;
+};
+
+/* Define the version so that tst-version-hash-zero-refmod.so passes
+ the initial symbol version check. */
+OTHER_VERSION {
+} Base;
+
+/* This version string hashes to zero. */
+PPPPPPPPPPPP {
+ global: global_variable;
+} Base;
diff --git a/elf/tst-version-hash-zero-refmod.c b/elf/tst-version-hash-zero-refmod.c
new file mode 100644
index 0000000000000000..cd8b3dcef5b82012
--- /dev/null
+++ b/elf/tst-version-hash-zero-refmod.c
@@ -0,0 +1,23 @@
+/* Test module that triggers a relocation failure in tst-version-hash-zero.
+ 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; see the file COPYING.LIB. If
+ not, see <https://www.gnu.org/licenses/>. */
+
+/* This is bound to global_variable@@OTHER_VERSION via
+ tst-version-hash-zero-linkmod.so, but at run time, only
+ global_variable@PPPPPPPPPPPP exists. */
+extern int global_variable;
+int *pointer_variable = &global_variable;
diff --git a/elf/tst-version-hash-zero.c b/elf/tst-version-hash-zero.c
new file mode 100644
index 0000000000000000..66a0db4f51fa0e10
--- /dev/null
+++ b/elf/tst-version-hash-zero.c
@@ -0,0 +1,56 @@
+/* Symbols with version hash zero should not match any version (bug 29190).
+ 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; see the file COPYING.LIB. If
+ not, see <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <stddef.h>
+#include <string.h>
+
+static int
+do_test (void)
+{
+ void *handle = xdlopen ("tst-version-hash-zero-mod.so", RTLD_NOW);
+
+ /* This used to crash because some struct r_found_version entries
+ with hash zero did not have valid version strings. */
+ TEST_VERIFY (xdlvsym (handle, "global_variable", "PPPPPPPPPPPP") != NULL);
+
+ /* Consistency check. */
+ TEST_VERIFY (xdlsym (handle, "global_variable")
+ == xdlvsym (handle, "global_variable", "PPPPPPPPPPPP"));
+
+ /* This symbol version is supposed to be missing. */
+ TEST_VERIFY (dlvsym (handle, "global_variable", "OTHER_VERSION") == NULL);
+
+ /* tst-version-hash-zero-refmod.so references
+ global_variable@@OTHER_VERSION and is expected to fail to load.
+ dlvsym sets the hidden flag during lookup. Relocation does not,
+ so this exercises a different failure case. */
+ TEST_VERIFY_EXIT (dlopen ("tst-version-hash-zero-refmod.so", RTLD_NOW)
+ == NULL);
+ const char *message = dlerror ();
+ if (strstr (message,
+ ": undefined symbol: global_variable, version OTHER_VERSION")
+ == NULL)
+ FAIL_EXIT1 ("unexpected dlopen failure: %s", message);
+
+ xdlclose (handle);
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,217 @@
commit 24c94ea84e9323dc24ce11f34368531f75eb9a72
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Mar 11 15:30:52 2025 +0100
elf: Test dlopen (NULL, RTLD_LAZY) from an ELF constructor
This call must not complete initialization of all shared objects
in the global scope because the ELF constructor which makes the call
likely has not finished initialization. Calling more constructors
at this point would expose those to a partially constructed
dependency.
This completes the revert of commit 9897ced8e78db5d813166a7ccccfd5a
("elf: Run constructors on cyclic recursive dlopen (bug 31986)").
(cherry picked from commit d604f9c500570e80febfcc6a52b63a002b466f35)
diff --git a/elf/Makefile b/elf/Makefile
index 10c54be629124a17..a102373793fd16bd 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -415,6 +415,7 @@ tests += \
tst-dlmopen3 \
tst-dlmopen4 \
tst-dlopen-auditdup \
+ tst-dlopen-constructor-null \
tst-dlopen-self \
tst-dlopen-tlsmodid \
tst-dlopen-tlsreinit1 \
@@ -865,6 +866,8 @@ modules-names += \
tst-dlmopen1mod \
tst-dlopen-auditdup-auditmod \
tst-dlopen-auditdupmod \
+ tst-dlopen-constructor-null-mod1 \
+ tst-dlopen-constructor-null-mod2 \
tst-dlopen-sgid-mod \
tst-dlopen-tlsreinitmod1 \
tst-dlopen-tlsreinitmod2 \
@@ -3199,3 +3202,9 @@ LDFLAGS-tst-version-hash-zero-linkmod.so = \
$(objpfx)tst-version-hash-zero-refmod.so: \
$(objpfx)tst-version-hash-zero-linkmod.so
tst-version-hash-zero-refmod.so-no-z-defs = yes
+
+$(objpfx)tst-dlopen-constructor-null: \
+ $(objpfx)tst-dlopen-constructor-null-mod1.so \
+ $(objpfx)tst-dlopen-constructor-null-mod2.so
+$(objpfx)tst-dlopen-constructor-null-mod2.so: \
+ $(objpfx)tst-dlopen-constructor-null-mod1.so
diff --git a/elf/dl-open.c b/elf/dl-open.c
index b00f283c42d19adb..80f084d5c838fc1c 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -605,6 +605,16 @@ dl_open_worker_begin (void *a)
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
add_to_global_update (new);
+ /* It is not possible to run the ELF constructor for the new
+ link map if it has not executed yet: If this dlopen call came
+ from an ELF constructor that has not put that object into a
+ consistent state, completing initialization for the entire
+ scope will expose objects that have this partially
+ constructed object among its dependencies to this
+ inconsistent state. This could happen even with a benign
+ dlopen (NULL, RTLD_LAZY) call from a constructor of an
+ initially loaded shared object. */
+
return;
}
diff --git a/elf/tst-dlopen-constructor-null-mod1.c b/elf/tst-dlopen-constructor-null-mod1.c
new file mode 100644
index 0000000000000000..70a7a0ad46a1a666
--- /dev/null
+++ b/elf/tst-dlopen-constructor-null-mod1.c
@@ -0,0 +1,55 @@
+/* Module calling dlopen (NULL, RTLD_LAZY) to obtain the global scope.
+ Copyright (C) 2024 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 <dlfcn.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int mod1_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ puts ("info: tst-dlopen-constructor-null-mod1.so constructor");
+
+ void *handle = dlopen (NULL, RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: %s\n", dlerror ());
+ exit (1);
+ }
+ puts ("info: dlopen returned");
+ if (dlsym (handle, "malloc") != malloc)
+ {
+ puts ("error: dlsym did not produce expected result");
+ exit (1);
+ }
+ dlclose (handle);
+
+ /* Check that the second module's constructor has not executed. */
+ if (getenv ("mod2_status") != NULL)
+ {
+ printf ("error: mod2_status environment variable set: %s\n",
+ getenv ("mod2_status"));
+ exit (1);
+ }
+
+ /* Communicate to the second module that the constructor executed. */
+ mod1_status = 1;
+}
diff --git a/elf/tst-dlopen-constructor-null-mod2.c b/elf/tst-dlopen-constructor-null-mod2.c
new file mode 100644
index 0000000000000000..d6e945beaec04815
--- /dev/null
+++ b/elf/tst-dlopen-constructor-null-mod2.c
@@ -0,0 +1,37 @@
+/* Module whose constructor should not be invoked by dlopen (NULL, RTLD_LAZY).
+ Copyright (C) 2024 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 <stdio.h>
+#include <stdlib.h>
+
+extern int mod1_status;
+int mod2_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ printf ("info: tst-dlopen-constructor-null-mod2.so constructor"
+ " (mod1_status=%d)", mod1_status);
+ if (!(mod1_status == 1 && mod2_status == 0))
+ {
+ puts ("error: mod1_status == 1 && mod2_status == 0 expected");
+ exit (1);
+ }
+ setenv ("mod2_status", "constructed", 1);
+ mod2_status = 1;
+}
diff --git a/elf/tst-dlopen-constructor-null.c b/elf/tst-dlopen-constructor-null.c
new file mode 100644
index 0000000000000000..db90643325c5235f
--- /dev/null
+++ b/elf/tst-dlopen-constructor-null.c
@@ -0,0 +1,38 @@
+/* Verify that dlopen (NULL, RTLD_LAZY) does not complete initialization.
+ Copyright (C) 2024 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/>. */
+
+/* This test mimics what the glvndSetupPthreads function in libglvnd
+ does. */
+
+#include <stdlib.h>
+#include <support/check.h>
+
+/* Defined and initialized in the shared objects. */
+extern int mod1_status;
+extern int mod2_status;
+
+static int
+do_test (void)
+{
+ TEST_COMPARE (mod1_status, 1);
+ TEST_COMPARE (mod2_status, 1);
+ TEST_COMPARE_STRING (getenv ("mod2_status"), "constructed");
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,159 @@
commit 5601ad79b75f03db3e30fc3358e63c1122985f95
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jul 4 21:46:05 2025 +0200
elf: Introduce separate _r_debug_array variable
It replaces the ns_debug member of the namespaces. Previously,
the base namespace had an unused ns_debug member.
This change also fixes a concurrency issue: Now _dl_debug_initialize
only updates r_next of the previous namespace's r_debug after the new
r_debug is initialized, so that only the initialized version is
observed. (Client code accessing _r_debug will benefit from load
dependency tracking in CPUs even without explicit barriers.)
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 7278d11f3a0cd528188c719bab75575b0aea2c6e)
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index ef56de7a29565652..5c49fa847e91bd81 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -30,17 +30,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
&& VERIFY_MEMBER (l_prev))
? 1 : -1];
+#ifdef SHARED
+/* r_debug structs for secondary namespaces. The first namespace is
+ handled separately because its r_debug structure must overlap with
+ the public _r_debug symbol, so the first array element corresponds
+ to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */
+struct r_debug_extended _r_debug_array[DL_NNS - 1];
+
+/* Return the r_debug object for the namespace NS. */
+static inline struct r_debug_extended *
+get_rdebug (Lmid_t ns)
+{
+ if (ns == LM_ID_BASE)
+ return &_r_debug_extended;
+ else
+ return &_r_debug_array[ns - 1];
+}
+#else /* !SHARED */
+static inline struct r_debug_extended *
+get_rdebug (Lmid_t ns)
+{
+ return &_r_debug_extended; /* There is just one namespace. */
+}
+#endif /* !SHARED */
+
/* Update the `r_map' member and return the address of `struct r_debug'
of the namespace NS. */
struct r_debug *
_dl_debug_update (Lmid_t ns)
{
- struct r_debug_extended *r;
- if (ns == LM_ID_BASE)
- r = &_r_debug_extended;
- else
- r = &GL(dl_ns)[ns]._ns_debug;
+ struct r_debug_extended *r = get_rdebug (ns);
if (r->base.r_map == NULL)
atomic_store_release (&r->base.r_map,
(void *) GL(dl_ns)[ns]._ns_loaded);
@@ -54,34 +74,7 @@ _dl_debug_update (Lmid_t ns)
struct r_debug *
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
{
- struct r_debug_extended *r, **pp = NULL;
-
- if (ns == LM_ID_BASE)
- {
- r = &_r_debug_extended;
- /* Initialize r_version to 1. */
- if (_r_debug_extended.base.r_version == 0)
- _r_debug_extended.base.r_version = 1;
- }
- else if (DL_NNS > 1)
- {
- r = &GL(dl_ns)[ns]._ns_debug;
- if (r->base.r_brk == 0)
- {
- /* Add the new namespace to the linked list. After a namespace
- is initialized, r_brk becomes non-zero. A namespace becomes
- empty (r_map == NULL) when it is unused. But it is never
- removed from the linked list. */
- struct r_debug_extended *p;
- for (pp = &_r_debug_extended.r_next;
- (p = *pp) != NULL;
- pp = &p->r_next)
- ;
-
- r->base.r_version = 2;
- }
- }
-
+ struct r_debug_extended *r = get_rdebug (ns);
if (r->base.r_brk == 0)
{
/* Tell the debugger where to find the map of loaded objects.
@@ -89,20 +82,36 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
only once. */
r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
- r->r_next = NULL;
+
+#ifdef SHARED
+ /* Add the new namespace to the linked list. This assumes that
+ namespaces are allocated in increasing order. After a
+ namespace is initialized, r_brk becomes non-zero. A
+ namespace becomes empty (r_map == NULL) when it is unused.
+ But it is never removed from the linked list. */
+
+ if (ns != LM_ID_BASE)
+ {
+ r->base.r_version = 2;
+ if (ns - 1 == LM_ID_BASE)
+ {
+ atomic_store_release (&_r_debug_extended.r_next, r);
+ /* Now there are multiple namespaces. */
+ atomic_store_release (&_r_debug_extended.base.r_version, 2);
+ }
+ else
+ /* Update r_debug_extended of the previous namespace. */
+ atomic_store_release (&_r_debug_array[ns - 2].r_next, r);
+ }
+ else
+#endif /* SHARED */
+ r->base.r_version = 1;
}
if (r->base.r_map == NULL)
atomic_store_release (&r->base.r_map,
(void *) GL(dl_ns)[ns]._ns_loaded);
- if (pp != NULL)
- {
- atomic_store_release (pp, r);
- /* Bump r_version to 2 for the new namespace. */
- atomic_store_release (&_r_debug_extended.base.r_version, 2);
- }
-
return &r->base;
}
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 91447a5e77c2466d..8b9ae3783056a29f 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -350,8 +350,6 @@ struct rtld_global
size_t n_elements;
void (*free) (void *);
} _ns_unique_sym_table;
- /* Keep track of changes to each namespace' list. */
- struct r_debug_extended _ns_debug;
} _dl_ns[DL_NNS];
/* One higher than index of last used namespace. */
EXTERN size_t _dl_nns;

View File

@ -0,0 +1,149 @@
commit 97017da5ef946c6d38c252f56c8cb7c205b732fa
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jul 4 21:46:16 2025 +0200
elf: Introduce _dl_debug_change_state
It combines updating r_state with the debugger notification.
The second change to _dl_open introduces an additional debugger
notification for dlmopen, but debuggers are expected to ignore it.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 8329939a37f483a16013dd8af8303cbcb86d92cb)
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 4c963097f4dc8d79..fb27a1231c1c5b66 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -433,8 +433,7 @@ _dl_close_worker (struct link_map *map, bool force)
/* Notify the debugger we are about to remove some loaded objects.
LA_ACT_DELETE has already been signalled above for !unload_any. */
struct r_debug *r = _dl_debug_update (nsid);
- r->r_state = RT_DELETE;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_DELETE);
LIBC_PROBE (unmap_start, 2, nsid, r);
if (unload_global)
@@ -726,8 +725,7 @@ _dl_close_worker (struct link_map *map, bool force)
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
/* Notify the debugger those objects are finalized and gone. */
- r->r_state = RT_CONSISTENT;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_CONSISTENT);
LIBC_PROBE (unmap_complete, 2, nsid, r);
#ifdef SHARED
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index 5c49fa847e91bd81..b3777ffc136469cf 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -67,6 +67,13 @@ _dl_debug_update (Lmid_t ns)
return &r->base;
}
+void
+_dl_debug_change_state (struct r_debug *r, int state)
+{
+ atomic_store_release (&r->r_state, state);
+ _dl_debug_state ();
+}
+
/* Initialize _r_debug_extended for the namespace NS. LDBASE is the
run-time load address of the dynamic linker, to be put in
_r_debug_extended.r_ldbase. Return the address of _r_debug. */
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 75a7187c649e0202..8b0890499d66f67a 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -947,8 +947,7 @@ _dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l)
/* Notify the debugger we have added some objects. We need to
call _dl_debug_initialize in a static program in case dynamic
linking has not been used before. */
- r->r_state = RT_ADD;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_ADD);
LIBC_PROBE (map_start, 2, nsid, r);
}
else
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 80f084d5c838fc1c..6f6d3ddbf94c764c 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -792,8 +792,7 @@ dl_open_worker (void *a)
#ifdef SHARED
bool was_not_consistent = r->r_state != RT_CONSISTENT;
#endif
- r->r_state = RT_CONSISTENT;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_CONSISTENT);
LIBC_PROBE (map_complete, 3, nsid, r, args->map);
#ifdef SHARED
@@ -871,7 +870,7 @@ no more namespaces available for dlmopen()"));
}
GL(dl_ns)[nsid].libc_map = NULL;
- _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
+ _dl_debug_change_state (_dl_debug_update (nsid), RT_CONSISTENT);
}
/* Never allow loading a DSO in a namespace which is empty. Such
direct placements is only causing problems. Also don't allow
diff --git a/elf/rtld.c b/elf/rtld.c
index 809fc807989b285e..43bfc7378afc6cc7 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1850,8 +1850,7 @@ dl_main (const ElfW(Phdr) *phdr,
elf_setup_debug_entry (main_map, r);
/* We start adding objects. */
- r->r_state = RT_ADD;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_ADD);
LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
/* Auditing checkpoint: we are ready to signal that the initial map
@@ -2402,8 +2401,7 @@ dl_main (const ElfW(Phdr) *phdr,
/* Notify the debugger all new objects are now ready to go. We must re-get
the address since by now the variable might be in another object. */
r = _dl_debug_update (LM_ID_BASE);
- r->r_state = RT_CONSISTENT;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_CONSISTENT);
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
/* Auditing checkpoint: we have added all objects. */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 8b9ae3783056a29f..017406e7fa93c941 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1067,8 +1067,14 @@ extern void _dl_debug_state (void);
rtld_hidden_proto (_dl_debug_state)
/* Initialize `struct r_debug_extended' for the namespace NS. LDBASE
- is the run-time load address of the dynamic linker, to be put in the
- `r_ldbase' member. Return the address of the structure. */
+ is the run-time load address of the dynamic linker, to be put in
+ the `r_ldbase' member.
+
+ Return the address of the r_debug structure for the namespace.
+ This is not merely a convenience or optimization, but it is
+ necessary for the LIBC_PROBE Systemtap/debugger probes to work
+ reliably: direct variable access can create probes that tools
+ cannot consume. */
extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
attribute_hidden;
@@ -1076,6 +1082,10 @@ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
of the namespace NS. */
extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
+/* Update R->r_state to STATE and notify the debugger by calling
+ _dl_debug_state. */
+void _dl_debug_change_state (struct r_debug *r, int state) attribute_hidden;
+
/* Initialize the basic data structure for the search paths. SOURCE
is either "LD_LIBRARY_PATH" or "--library-path".
GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to

View File

@ -0,0 +1,252 @@
commit 5cd1f4b1a1eaf7774821d81bbd0222d80a927db2
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jul 4 21:46:30 2025 +0200
elf: Restore support for _r_debug interpositions and copy relocations
The changes in commit a93d9e03a31ec14405cb3a09aa95413b67067380
("Extend struct r_debug to support multiple namespaces [BZ #15971]")
break the dyninst dynamic instrumentation tool. It brings its
own definition of _r_debug (rather than a declaration).
Furthermore, it turns out it is rather hard to use the proposed
handshake for accessing _r_debug via DT_DEBUG. If applications want
to access _r_debug, they can do so directly if the relevant code has
been built as PIC. To protect against harm from accidental copy
relocations due to linker relaxations, this commit restores copy
relocation support by adjusting both copies if interposition or
copy relocations are in play. Therefore, it is possible to
use a hidden reference in ld.so to access _r_debug.
Only perform the copy relocation initialization if libc has been
loaded. Otherwise, the ld.so search scope can be empty, and the
lookup of the _r_debug symbol mail fail.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit ea85e7d55087075376a29261e722e4fae14ecbe7)
diff --git a/elf/Makefile b/elf/Makefile
index a102373793fd16bd..34933bb15f2d8228 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -414,6 +414,8 @@ tests += \
tst-dlmopen1 \
tst-dlmopen3 \
tst-dlmopen4 \
+ tst-dlmopen4-nonpic \
+ tst-dlmopen4-pic \
tst-dlopen-auditdup \
tst-dlopen-constructor-null \
tst-dlopen-self \
@@ -2062,6 +2064,13 @@ $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
$(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so
+CFLAGS-tst-dlmopen4-pic.c += -fPIC
+$(objpfx)tst-dlmopen4-pic.out: $(objpfx)tst-dlmopen1mod.so
+
+CFLAGS-tst-dlmopen4-nonpic.c += -fno-pie
+tst-dlmopen4-nonpic-no-pie = yes
+$(objpfx)tst-dlmopen4-nonpic.out: $(objpfx)tst-dlmopen1mod.so
+
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S
index 4e35adef5de5db33..33f0fc77de503aea 100644
--- a/elf/dl-debug-symbols.S
+++ b/elf/dl-debug-symbols.S
@@ -38,3 +38,4 @@
_r_debug:
_r_debug_extended:
.zero R_DEBUG_EXTENDED_SIZE
+rtld_hidden_def (_r_debug)
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index b3777ffc136469cf..8b513323091402db 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <assert.h>
#include <ldsodefs.h>
@@ -37,6 +38,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */
struct r_debug_extended _r_debug_array[DL_NNS - 1];
+/* If not null, pointer to the _r_debug in the main executable. */
+static struct r_debug *_r_debug_main;
+
+void
+_dl_debug_post_relocate (struct link_map *main_map)
+{
+ /* Perform a full symbol search in all objects, to maintain
+ compatibility if interposed _r_debug definitions. The lookup
+ cannot fail because there is a definition in ld.so, and this
+ function is only called if the ld.so search scope is not empty. */
+ const ElfW(Sym) *sym = NULL;
+ lookup_t result =_dl_lookup_symbol_x ("_r_debug", main_map, &sym,
+ main_map->l_scope, NULL, 0, 0, NULL);
+ if (sym->st_size >= sizeof (struct r_debug))
+ {
+ struct r_debug *main_r_debug = DL_SYMBOL_ADDRESS (result, sym);
+ if (main_r_debug != &_r_debug_extended.base)
+ {
+ /* The extended version of the struct is not available in
+ the main executable because a copy relocation has been
+ used. r_map etc. have already been copied as part of the
+ copy relocation processing. */
+ main_r_debug->r_version = 1;
+
+ /* Record that dual updates of the initial link map are
+ required. */
+ _r_debug_main = main_r_debug;
+ }
+ }
+}
+
/* Return the r_debug object for the namespace NS. */
static inline struct r_debug_extended *
get_rdebug (Lmid_t ns)
@@ -71,6 +103,11 @@ void
_dl_debug_change_state (struct r_debug *r, int state)
{
atomic_store_release (&r->r_state, state);
+#ifdef SHARED
+ if (r == &_r_debug_extended.base && _r_debug_main != NULL)
+ /* Update the copy-relocation of _r_debug. */
+ atomic_store_release (&_r_debug_main->r_state, state);
+#endif
_dl_debug_state ();
}
@@ -103,7 +140,9 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
if (ns - 1 == LM_ID_BASE)
{
atomic_store_release (&_r_debug_extended.r_next, r);
- /* Now there are multiple namespaces. */
+ /* Now there are multiple namespaces. Note that this
+ deliberately does not update the copy in the main
+ executable (if it exists). */
atomic_store_release (&_r_debug_extended.base.r_version, 2);
}
else
@@ -116,8 +155,15 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
}
if (r->base.r_map == NULL)
- atomic_store_release (&r->base.r_map,
- (void *) GL(dl_ns)[ns]._ns_loaded);
+ {
+ struct link_map_public *l = (void *) GL(dl_ns)[ns]._ns_loaded;
+ atomic_store_release (&r->base.r_map, l);
+#ifdef SHARED
+ if (ns == LM_ID_BASE && _r_debug_main != NULL)
+ /* Update the copy-relocation of _r_debug. */
+ atomic_store_release (&_r_debug_main->r_map, l);
+#endif
+ }
return &r->base;
}
diff --git a/elf/rtld.c b/elf/rtld.c
index 43bfc7378afc6cc7..cd790e37f2a323a4 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2381,6 +2381,9 @@ dl_main (const ElfW(Phdr) *phdr,
__rtld_mutex_init ();
__rtld_malloc_init_real (main_map);
+
+ /* Update copy-relocated _r_debug if necessary. */
+ _dl_debug_post_relocate (main_map);
}
/* All ld.so initialization is complete. Apply RELRO. */
diff --git a/elf/tst-dlmopen4-nonpic.c b/elf/tst-dlmopen4-nonpic.c
new file mode 100644
index 0000000000000000..ad4e40995337f4f9
--- /dev/null
+++ b/elf/tst-dlmopen4-nonpic.c
@@ -0,0 +1,2 @@
+#define BUILD_FOR_NONPIC
+#include "tst-dlmopen4.c"
diff --git a/elf/tst-dlmopen4-pic.c b/elf/tst-dlmopen4-pic.c
new file mode 100644
index 0000000000000000..919fa85c2579fb5d
--- /dev/null
+++ b/elf/tst-dlmopen4-pic.c
@@ -0,0 +1,2 @@
+#define BUILD_FOR_PIC
+#include "tst-dlmopen4.c"
diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
index b1c5502621ed433d..9e053fbc59c531ae 100644
--- a/elf/tst-dlmopen4.c
+++ b/elf/tst-dlmopen4.c
@@ -46,6 +46,15 @@ do_test (void)
TEST_COMPARE (debug->base.r_version, 1);
TEST_VERIFY_EXIT (debug->r_next == NULL);
+#ifdef BUILD_FOR_PIC
+ /* In a PIC build, using _r_debug directly should give us the same
+ object. */
+ TEST_VERIFY (&_r_debug == &debug->base);
+#endif
+#ifdef BUILD_FOR_NONPIC
+ TEST_COMPARE (_r_debug.r_version, 1);
+#endif
+
void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
RTLD_LAZY);
@@ -57,6 +66,19 @@ do_test (void)
const char *name = basename (debug->r_next->base.r_map->l_name);
TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so");
+#ifdef BUILD_FOR_NONPIC
+ /* If a copy relocation is used, it must be at version 1. */
+ if (&_r_debug != &debug->base)
+ {
+ TEST_COMPARE (_r_debug.r_version, 1);
+ TEST_COMPARE ((uintptr_t) _r_debug.r_map,
+ (uintptr_t) debug->base.r_map);
+ TEST_COMPARE (_r_debug.r_brk, debug->base.r_brk);
+ TEST_COMPARE (_r_debug.r_state, debug->base.r_state);
+ TEST_COMPARE (_r_debug.r_ldbase, debug->base.r_ldbase);
+ }
+#endif
+
xdlclose (h);
return 0;
diff --git a/include/link.h b/include/link.h
index 5ed445d5a6cdf12d..7ca305f7804442f5 100644
--- a/include/link.h
+++ b/include/link.h
@@ -365,6 +365,8 @@ struct auditstate
dynamic linker. */
extern struct r_debug_extended _r_debug_extended attribute_hidden;
+rtld_hidden_proto (_r_debug)
+
#if __ELF_NATIVE_CLASS == 32
# define symbind symbind32
# define LA_SYMBIND "la_symbind32"
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 017406e7fa93c941..043abd369700ad58 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1078,6 +1078,10 @@ rtld_hidden_proto (_dl_debug_state)
extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
attribute_hidden;
+/* This is called after relocation processing to handle a potential
+ copy relocation for _r_debug. */
+void _dl_debug_post_relocate (struct link_map *main_map) attribute_hidden;
+
/* Update the `r_map' member and return the address of `struct r_debug'
of the namespace NS. */
extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;

View File

@ -0,0 +1,81 @@
commit cf0e7d512d3c5a5d46da50c0aa023a7f8dc0d560
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jul 28 14:16:52 2025 +0200
elf: Compile _dl_debug_state separately (bug 33224)
This ensures that the compiler will not inline it, so that
debuggers which do not use the Systemtap probes can reliably
set a breakpoint on it.
Reviewed-by: Andreas K. Huettel <dilfridge@gentoo.org>
Tested-by: Andreas K. Huettel <dilfridge@gentoo.org>
(cherry picked from commit 620f0730f311635cd0e175a3ae4d0fc700c76366)
diff --git a/elf/Makefile b/elf/Makefile
index 34933bb15f2d8228..57726b1034046433 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -57,6 +57,7 @@ dl-routines = \
dl-close \
dl-debug \
dl-debug-symbols \
+ dl-debug_state \
dl-deps \
dl-exception \
dl-execstack \
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index 8b513323091402db..df36d61dcb66dd0f 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -167,14 +167,3 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
return &r->base;
}
-
-
-/* This function exists solely to have a breakpoint set on it by the
- debugger. The debugger is supposed to find this function's address by
- examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
- for this particular symbol name in the PT_INTERP file. */
-void
-_dl_debug_state (void)
-{
-}
-rtld_hidden_def (_dl_debug_state)
diff --git a/elf/dl-debug_state.c b/elf/dl-debug_state.c
new file mode 100644
index 0000000000000000..40c134a49e2455f3
--- /dev/null
+++ b/elf/dl-debug_state.c
@@ -0,0 +1,30 @@
+/* Debugger hook called after dynamic linker updates.
+ Copyright (C) 1996-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/>. */
+
+#include <ldsodefs.h>
+
+/* This function exists solely to have a breakpoint set on it by the
+ debugger. The debugger is supposed to find this function's address by
+ examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
+ for this particular symbol name in the PT_INTERP file. Therefore,
+ this function must not be inlined. */
+void
+_dl_debug_state (void)
+{
+}
+rtld_hidden_def (_dl_debug_state)

View File

@ -0,0 +1,23 @@
commit 4c2509882fd9768a067ce8cb7cb40394e1cf3862
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Aug 18 13:52:02 2025 +0200
elf: Preserve _rtld_global layout for the release branch
Backporting commit 97017da5ef946c6d38c252f56c8cb7c205b732fa
("elf: Introduce _dl_debug_change_state") removed the
_ns_debug member. Keep it to preseve struct layout.
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 043abd369700ad58..b4c6e6d2ca7a1fec 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -350,6 +350,8 @@ struct rtld_global
size_t n_elements;
void (*free) (void *);
} _ns_unique_sym_table;
+ /* Keep track of changes to each namespace' list. */
+ struct r_debug_extended _ns_debug_unused;
} _dl_ns[DL_NNS];
/* One higher than index of last used namespace. */
EXTERN size_t _dl_nns;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
commit 5541edb1bd57414556c8dfe08493ae4b8694e4b4
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Aug 18 09:06:48 2025 -0700
i386: Also add GLIBC_ABI_GNU2_TLS version [BZ #33129]
Since the GNU2 TLS run-time bug:
https://sourceware.org/bugzilla/show_bug.cgi?id=31372
affects both i386 and x86-64, also add GLIBC_ABI_GNU2_TLS version to i386
to indicate the working GNU2 TLS run-time. For x86-64, the additional
GNU2 TLS run-time bug fix is needed for
https://sourceware.org/bugzilla/show_bug.cgi?id=31501
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit bd4628f3f18ac312408782eea450429c6f044860)
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index f64cee3cd9a13c3e..c814060e08b3ceeb 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -127,6 +127,15 @@ LDFLAGS-tst-tls23 += -rdynamic
tst-tls23-mod.so-no-z-defs = yes
$(objpfx)tst-tls23-mod.so: $(libsupport)
+
+tests-special += $(objpfx)check-gnu2-tls.out
+
+$(objpfx)check-gnu2-tls.out: $(common-objpfx)libc.so
+ LC_ALL=C $(READELF) -V -W $< \
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
+ | grep GLIBC_ABI_GNU2_TLS > $@; \
+ $(evaluate-test)
+generated += check-gnu2-tls.out
endif
ifeq ($(subdir),math)
diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions
index 33dbd67b64c3ab5e..06f414bc148340bd 100644
--- a/sysdeps/x86/Versions
+++ b/sysdeps/x86/Versions
@@ -8,4 +8,9 @@ libc {
GLIBC_2.33 {
__x86_get_cpuid_feature_leaf;
}
+ GLIBC_ABI_GNU2_TLS {
+ # This symbol is used only for empty version map and will be removed
+ # by scripts/versions.awk.
+ __placeholder_only_for_empty_version_map;
+ }
}
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index a738e0178220d9ca..c97b3ac13af248c0 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -215,15 +215,6 @@ $(objpfx)check-dt-x86-64-plt.out: $(common-objpfx)libc.so
| grep GLIBC_ABI_DT_X86_64_PLT > $@; \
$(evaluate-test)
generated += check-dt-x86-64-plt.out
-
-tests-special += $(objpfx)check-gnu2-tls.out
-
-$(objpfx)check-gnu2-tls.out: $(common-objpfx)libc.so
- LC_ALL=C $(READELF) -V -W $< \
- | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
- | grep GLIBC_ABI_GNU2_TLS > $@; \
- $(evaluate-test)
-generated += check-gnu2-tls.out
endif
test-internal-extras += tst-gnu2-tls2mod1
diff --git a/sysdeps/x86_64/Versions b/sysdeps/x86_64/Versions
index 0a759029e5a00cf1..6a989ad3b373cdf6 100644
--- a/sysdeps/x86_64/Versions
+++ b/sysdeps/x86_64/Versions
@@ -5,11 +5,6 @@ libc {
GLIBC_2.13 {
__fentry__;
}
- GLIBC_ABI_GNU2_TLS {
- # This symbol is used only for empty version map and will be removed
- # by scripts/versions.awk.
- __placeholder_only_for_empty_version_map;
- }
GLIBC_ABI_DT_X86_64_PLT {
# This symbol is used only for empty version map and will be removed
# by scripts/versions.awk.

View File

@ -0,0 +1,60 @@
commit 83340b35ccb24dcda8b709c4683ab9eade454bd7
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Jul 28 12:16:11 2025 -0700
i386: Add GLIBC_ABI_GNU_TLS version [BZ #33221]
On i386, programs and shared libraries with __thread usage may fail
silently at run-time against glibc without the TLS run-time fix for:
https://sourceware.org/bugzilla/show_bug.cgi?id=32996
Add GLIBC_ABI_GNU_TLS version to indicate that glibc has the working
GNU TLS run-time. Linker can add the GLIBC_ABI_GNU_TLS version to
binaries which depend on the working TLS run-time so that such programs
and shared libraries will fail to load and run at run-time against
libc.so without the GLIBC_ABI_GNU_TLS version, instead of fail silently
at random.
This fixes BZ #33221.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit ed1b7a5a489ab555a27fad9c101ebe2e1c1ba881)
diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile
index ee6470d78e856315..c0c017b899ebccbe 100644
--- a/sysdeps/i386/Makefile
+++ b/sysdeps/i386/Makefile
@@ -60,6 +60,15 @@ $(objpfx)tst-ld-sse-use.out: ../sysdeps/i386/tst-ld-sse-use.sh $(objpfx)ld.so
@echo "Checking ld.so for SSE register use. This will take a few seconds..."
$(BASH) $< $(objpfx) '$(NM)' '$(OBJDUMP)' '$(READELF)' > $@; \
$(evaluate-test)
+
+tests-special += $(objpfx)check-gnu-tls.out
+
+$(objpfx)check-gnu-tls.out: $(common-objpfx)libc.so
+ LC_ALL=C $(READELF) -V -W $< \
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
+ | grep GLIBC_ABI_GNU_TLS > $@; \
+ $(evaluate-test)
+generated += check-gnu-tls.out
else
CFLAGS-.os += $(if $(filter rtld-%.os,$(@F)), $(rtld-CFLAGS))
endif
diff --git a/sysdeps/i386/Versions b/sysdeps/i386/Versions
index 36e23b466a622f43..9c84c8ef049eb18d 100644
--- a/sysdeps/i386/Versions
+++ b/sysdeps/i386/Versions
@@ -28,6 +28,11 @@ libc {
GLIBC_2.13 {
__fentry__;
}
+ GLIBC_ABI_GNU_TLS {
+ # This symbol is used only for empty version map and will be removed
+ # by scripts/versions.awk.
+ __placeholder_only_for_empty_version_map;
+ }
}
libm {
GLIBC_2.1 {

View File

@ -0,0 +1,61 @@
commit fffc2df8a3e2c8cda2991063d23086360268b777
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri May 16 19:53:09 2025 +0200
Optimize __libc_tsd_* thread variable access
These variables are not exported, and libc.so TLS is initial-exec
anyway. Declare these variables as hidden and use the initial-exec
TLS model.
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
(cherry picked from commit a894f04d877653bea1639fc9a4adf73bd9347bf4)
diff --git a/include/ctype.h b/include/ctype.h
index ae078a63d355af61..a15e5b66781535d4 100644
--- a/include/ctype.h
+++ b/include/ctype.h
@@ -29,9 +29,12 @@ libc_hidden_proto (toupper)
# define CTYPE_EXTERN_INLINE extern inline
# endif
-extern __thread const uint16_t * __libc_tsd_CTYPE_B;
-extern __thread const int32_t * __libc_tsd_CTYPE_TOUPPER;
-extern __thread const int32_t * __libc_tsd_CTYPE_TOLOWER;
+extern __thread const uint16_t * __libc_tsd_CTYPE_B
+ attribute_hidden attribute_tls_model_ie;
+extern __thread const int32_t * __libc_tsd_CTYPE_TOUPPER
+ attribute_hidden attribute_tls_model_ie;
+extern __thread const int32_t * __libc_tsd_CTYPE_TOLOWER
+ attribute_hidden attribute_tls_model_ie;
CTYPE_EXTERN_INLINE const uint16_t ** __attribute__ ((const))
diff --git a/include/rpc/rpc.h b/include/rpc/rpc.h
index 936ea3cebb8101e1..ba967833ad8d8ac3 100644
--- a/include/rpc/rpc.h
+++ b/include/rpc/rpc.h
@@ -45,7 +45,8 @@ extern void __rpc_thread_key_cleanup (void) attribute_hidden;
extern void __rpc_thread_destroy (void) attribute_hidden;
-extern __thread struct rpc_thread_variables *__libc_tsd_RPC_VARS;
+extern __thread struct rpc_thread_variables *__libc_tsd_RPC_VARS
+ attribute_hidden attribute_tls_model_ie;
#define RPC_THREAD_VARIABLE(x) (__rpc_thread_variables()->x)
diff --git a/locale/localeinfo.h b/locale/localeinfo.h
index bc8e92e4dca80d62..c3249d371537ad7d 100644
--- a/locale/localeinfo.h
+++ b/locale/localeinfo.h
@@ -237,7 +237,8 @@ extern struct __locale_struct _nl_global_locale attribute_hidden;
/* This fetches the thread-local locale_t pointer, either one set with
uselocale or &_nl_global_locale. */
#define _NL_CURRENT_LOCALE __libc_tsd_LOCALE
-extern __thread locale_t __libc_tsd_LOCALE;
+extern __thread locale_t __libc_tsd_LOCALE
+ attribute_hidden attribute_tls_model_ie;
/* For static linking it is desireable to avoid always linking in the code
and data for every category when we can tell at link time that they are

View File

@ -147,8 +147,8 @@ Version: %{glibcversion}
# - It allows using the Release number without the %%dist tag in the dependency
# generator to make the generated requires interchangeable between Rawhide
# and ELN (.elnYY < .fcXX).
%global baserelease 56
Release: %{baserelease}%{?dist}.alma.2
%global baserelease 58
Release: %{baserelease}%{?dist}.alma.1
# Licenses:
#
@ -699,6 +699,53 @@ Patch373: glibc-RHEL-108823-11.patch
Patch374: glibc-RHEL-108823-12.patch
Patch375: glibc-RHEL-108823-13.patch
Patch376: glibc-RHEL-108823-14.patch
# glibc-2.39-212-gb027d5b145 is glibc-RHEL-105324.patch.
Patch377: glibc-upstream-2.39-213.patch
Patch378: glibc-upstream-2.39-214.patch
Patch379: glibc-upstream-2.39-215.patch
Patch380: glibc-upstream-2.39-216.patch
Patch381: glibc-upstream-2.39-217.patch
Patch382: glibc-upstream-2.39-218.patch
Patch383: glibc-upstream-2.39-219.patch
Patch384: glibc-upstream-2.39-220.patch
Patch385: glibc-upstream-2.39-221.patch
Patch386: glibc-upstream-2.39-222.patch
Patch387: glibc-upstream-2.39-223.patch
Patch388: glibc-upstream-2.39-224.patch
Patch389: glibc-upstream-2.39-225.patch
# glibc-2.39-226-g42a8cb7560 is glibc-RHEL-108475-1.patch.
# glibc-2.39-227-gf0e8d04eef is glibc-RHEL-108475-2.patch.
Patch390: glibc-upstream-2.39-228.patch
Patch391: glibc-upstream-2.39-229.patch
Patch392: glibc-upstream-2.39-230.patch
Patch393: glibc-upstream-2.39-231.patch
Patch394: glibc-upstream-2.39-232.patch
Patch395: glibc-upstream-2.39-233.patch
Patch396: glibc-upstream-2.39-234.patch
Patch397: glibc-upstream-2.39-235.patch
Patch398: glibc-upstream-2.39-236.patch
Patch399: glibc-upstream-2.39-237.patch
Patch400: glibc-upstream-2.39-238.patch
Patch401: glibc-upstream-2.39-239.patch
Patch402: glibc-upstream-2.39-240.patch
Patch403: glibc-upstream-2.39-241.patch
Patch404: glibc-upstream-2.39-242.patch
Patch405: glibc-upstream-2.39-243.patch
Patch406: glibc-upstream-2.39-244.patch
Patch407: glibc-upstream-2.39-245.patch
Patch408: glibc-upstream-2.39-246.patch
Patch409: glibc-upstream-2.39-247.patch
Patch410: glibc-upstream-2.39-248.patch
Patch411: glibc-upstream-2.39-249.patch
Patch412: glibc-upstream-2.39-250.patch
Patch413: glibc-upstream-2.39-251.patch
Patch414: glibc-upstream-2.39-252.patch
Patch415: glibc-upstream-2.39-253.patch
# glibc-2.39-254-g3b6c8ea878 is glibc-RHEL-106562-16.patch.
# glibc-2.39-255-g1f17635507 is glibc-RHEL-106562-17.patch.
Patch416: glibc-upstream-2.39-256.patch
Patch417: glibc-upstream-2.39-257.patch
Patch418: glibc-upstream-2.39-258.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -716,6 +763,9 @@ Provides: rtld(GNU_HASH)
# We need libgcc for cancellation support in POSIX threads.
Requires: libgcc%{_isa}
# Encourage the package manager to break the libgcc/glibc dependency
# cycle by installing libgcc first. (This is the historic installation order.)
Requires(pre): libgcc%{_isa}
Requires: glibc-common = %{version}-%{release}
@ -2715,9 +2765,31 @@ update_gconv_modules_cache ()
%endif
%changelog
* Wed Aug 20 2025 Eduard Abdullin <eabdullin@almalinux.org> - 2.39-56.alma.2
* Fri Aug 22 2025 Eduard Abdullin <eabdullin@almalinux.org> - 2.39-58.alma.1
- Overwrite target for x86_64_v2
* Thu Aug 21 2025 Florian Weimer <fweimer@redhat.com> - 2.39-58
- Use Requires(pre): libgcc%{_isa} to break libgcc cycle (RHEL-110559)
* Thu Aug 21 2025 Arjun Shankar <arjun@redhat.com> - 2.39-57
- Sync with upstream branch release/2.39/master (RHEL-109536)
- Upstream commit: fffc2df8a3e2c8cda2991063d23086360268b777
- Extend struct r_debug to support multiple namespaces (RHEL-101985)
- Fix a potential crash in the dynamic loader when processing specific
symbol versions (RHEL-109683)
- Signal la_objopen for ld.so with dlmopen (RHEL-109693)
- Switch to main malloc after final ld.so self-relocation (RHEL-109703)
- Prevent ld.so from asserting and crashing during audited library loads
(RHEL-109702)
- x86-64: Provide GLIBC_ABI_DT_X86_64_PLT symbol version (RHEL-109621)
- x86-64: Provide GLIBC_ABI_GNU2_TLS symbol version (RHEL-109625)
- Ensure fallback initialization of ctype TLS data pointers to fix segfaults in
programs using dlmopen or auditors (RHEL-72018)
- Handle load segment gaps in _dl_find_object (RHEL-104854)
- AArch64: Improve codegen in SVE log1p
- AArch64: Optimize inverse trig functions
- AArch64: Avoid memset ifunc in cpu-features.c [BZ #33112]
* Tue Aug 19 2025 Arjun Shankar <arjun@redhat.com> - 2.39-56
- Add FUSE based tests for fchmod, lstat, and mkstemp (RHEL-108823)