[PATCH 2/2] elf: Use the effective lazy mode for the deferred IRELATIVE pass

Adhemerval Zanella <[email protected]> Sun, 2 Aug 2026 20:44:04 -0300
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
The 63b31c05a8a split relocation processing must agree for the lazy
flag, a mistamatch would change the .rel.plt handling.

This is not an issue for any port currently, but on hppa it may return
a different value: if hppa affs IFUNC support, the second pass would
route PLT entries to its empty lazy handler and leave the descriptors
unrelocated, silently.

Checked on x86_64-linux-gnu, and built for all supported architectures.
---
 elf/dl-reloc-static-pie.c |  7 +++++--
 elf/dl-reloc.c            |  5 +++--
 elf/dynamic-link.h        | 21 ++++++++++++++-------
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
index 53260b57372..79aa2c24327 100644
--- a/elf/dl-reloc-static-pie.c
+++ b/elf/dl-reloc-static-pie.c
@@ -79,8 +79,11 @@ _dl_relocate_static_pie (void)
 # endif
 
   /* Relocate ourselves so we can do normal function calls and data access
-     using the global offset table.  IRELATIVE entries are deferred.  */
-  ELF_DYNAMIC_RELOCATE_NOIFUNC (main_map, NULL, 0, 0, 0);
+     using the global offset table.  IRELATIVE entries are deferred.
+     Lazy binding is never used here, so edr_lazy comes back as 0 and the
+     deferred pass can hardcode the same value.  */
+  int edr_lazy;
+  ELF_DYNAMIC_RELOCATE_NOIFUNC (main_map, NULL, 0, 0, 0, edr_lazy);
 
   /* Initialize _r_debug_extended.  */
   struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 80cd7e25d16..01f16f9a3ae 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -278,8 +278,9 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
        IFUNC resolvers.  Without this, a resolver would see the unrelocated
        initialiser bytes that were placed into the slot by the early
        _dl_allocate_tls_init.  */
+    int edr_lazy;
     ELF_DYNAMIC_RELOCATE_NOIFUNC (l, scope, lazy, consider_profiling,
-				  skip_ifunc);
+				  skip_ifunc, edr_lazy);
 
 #ifdef SHARED
     /* Re-initialise the static TLS slot with the .tdata so the IRELATIVE
@@ -292,7 +293,7 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
       _dl_init_static_tls (l);
 #endif
 
-    ELF_DYNAMIC_RELOCATE_IFUNC (l, scope, lazy, skip_ifunc);
+    ELF_DYNAMIC_RELOCATE_IFUNC (l, scope, edr_lazy, skip_ifunc);
 
     if ((consider_profiling || consider_symbind)
 	&& l->l_info[DT_PLTRELSZ] != NULL)
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 9baef6d7b84..0110ec56d3d 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -261,20 +261,27 @@ enum elf_dynamic_reloc_phase
 /* Like ELF_DYNAMIC_RELOCATE but only processes the non-IRELATIVE pass.
    The IRELATIVE pass must be completed later via ELF_DYNAMIC_RELOCATE_IFUNC.
    Used by the static-pie startup so the TCB and stack-protector canary can
-   be initialised between the two passes.  */
+   be initialised between the two passes.
+
+   EDR_LAZY is an int  which receives the effective lazy-binding mode picked
+   by elf_machine_runtime_setup.  It can differ from LAZY (currently only
+   hppa), and elf_machine_runtime_setup has side effects so it must not be
+   called twice.  The caller must pass the same value back to
+   ELF_DYNAMIC_RELOCATE_IFUNC.  */
 # define ELF_DYNAMIC_RELOCATE_NOIFUNC(map, scope, lazy, consider_profile,     \
-				      skip_ifunc)			      \
+				      skip_ifunc, edr_lazy)		      \
   do {									      \
-    int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy),	      \
-					      (consider_profile));	      \
+    (edr_lazy) = elf_machine_runtime_setup ((map), (scope), (lazy),	      \
+					    (consider_profile));	      \
     if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP)			      \
       ELF_DYNAMIC_DO_RELR (map);					      \
-    ELF_DYNAMIC_DO_REL_NOIFUNC ((map), (scope), edr_lazy, skip_ifunc);	      \
-    ELF_DYNAMIC_DO_RELA_NOIFUNC ((map), (scope), edr_lazy, skip_ifunc);	      \
+    ELF_DYNAMIC_DO_REL_NOIFUNC ((map), (scope), (edr_lazy), skip_ifunc);      \
+    ELF_DYNAMIC_DO_RELA_NOIFUNC ((map), (scope), (edr_lazy), skip_ifunc);     \
     ELF_DYNAMIC_AFTER_RELOC ((map), (edr_lazy));			      \
   } while (0)
 
-/* IRELATIVE-only companion to ELF_DYNAMIC_RELOCATE_NOIFUNC.  */
+/* IRELATIVE-only companion to ELF_DYNAMIC_RELOCATE_NOIFUNC.  LAZY must be the
+   EDR_LAZY value that call produced, not the mode originally requested.  */
 # define ELF_DYNAMIC_RELOCATE_IFUNC(map, scope, lazy, skip_ifunc)	      \
   do {									      \
     ELF_DYNAMIC_DO_REL_IFUNCONLY ((map), (scope), (lazy), skip_ifunc);	      \
-- 
2.53.0