[glibc] elf: Use the effective lazy mode for the deferred IRELATIVE pass

Adhemerval Zanella via Glibc-cvs <[email protected]>
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=16ad6a15393e2490f02bded0e0829b626ea02a29

commit 16ad6a15393e2490f02bded0e0829b626ea02a29
Author: Adhemerval Zanella <[email protected]>
Date:   Mon Aug 3 11:02:54 2026 -0300

    elf: Use the effective lazy mode for the deferred IRELATIVE pass
    
    The 63b31c05a8a split relocation processing must agree for the lazy
    flag, a mismatch 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 implements IFUNC support, the second pass would
    route PLT entries to its empty lazy handler and leave the descriptors
    unrelocated, silently.
    
    Make ELF_DYNAMIC_RELOCATE_PASS take lazy as an int lvalue and store the
    effective mode back into it, so the DL_RELOC_IRELATIVE call reuses the
    same variable instead of a separately threaded copy.  The two passes can no
    longer disagree about the partitioning.  elf_machine_runtime_setup has side
    effects, so it must stay a single call.
    
    Checked on x86_64-linux-gnu, and built for all supported architectures.
    
    Reviewed-by: Sam James <[email protected]>

Diff:
---
 elf/dl-reloc-static-pie.c | 12 +++++++++---
 elf/dl-reloc.c            |  5 +++--
 elf/dynamic-link.h        | 34 ++++++++++++++++++++++------------
 3 files changed, 34 insertions(+), 17 deletions(-)

diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
index 5dc5a545a8..a3d984f602 100644
--- a/elf/dl-reloc-static-pie.c
+++ b/elf/dl-reloc-static-pie.c
@@ -79,8 +79,12 @@ _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_PASS (DL_RELOC_NORMAL, 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 = 0;
+  ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, main_map, NULL, edr_lazy,
+			     0, 0);
 
   /* Initialize _r_debug_extended.  */
   struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
@@ -98,7 +102,9 @@ void
 _dl_relocate_static_pie_ifunc (void)
 {
   struct link_map *main_map = _dl_get_dl_main_map ();
-  ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, main_map, NULL, 0, 0, 0);
+  int edr_lazy = 0;
+  ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, main_map, NULL, edr_lazy,
+			     0, 0);
   main_map->l_relocated = 1;
 }
 #endif
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 6170d8689f..8077f90167 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -336,7 +336,8 @@ _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.  */
-    ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, l, scope, lazy,
+    int edr_lazy = lazy;
+    ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, l, scope, edr_lazy,
 			       consider_profiling, skip_ifunc);
 
 #ifdef SHARED
@@ -350,7 +351,7 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
       _dl_init_static_tls (l);
 #endif
 
-    ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, l, scope, lazy,
+    ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, l, scope, edr_lazy,
 			       0, skip_ifunc);
 
     if ((consider_profiling || consider_symbind)
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 0130c63feb..81a3f0856e 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -235,29 +235,39 @@ enum elf_dynamic_reloc_pass
    processed.  It is orthogonal to SKIP_IFUNC, which suppresses running IFUNC
    resolvers in whichever pass is selected.
 
-   Unless PASS is DL_RELOC_IRELATIVE, this also performs the machine-specific
-   PLT/GOT setup, the DT_RELR relocations, and the ELF_DYNAMIC_AFTER_RELOC
-   hook.  */
+   Unless PASS is DL_RELOC_IRELATIVE, this also performs the
+   machine-specific PLT/GOT setup, the DT_RELR relocations, and the
+   ELF_DYNAMIC_AFTER_RELOC hook.
+
+   LAZY must be an int lvalue.  elf_machine_runtime_setup may downgrade the
+   requested mode (currently only hppa, when it cannot install the lazy
+   trampoline) and it has side effects, so it must run exactly once (the
+   effective mode is stored back into LAZY).  A later DL_RELOC_IRELATIVE
+   call must be handed that same lvalue, so that both passes partition the
+   relocation ranges identically.  */
 # define ELF_DYNAMIC_RELOCATE_PASS(pass, map, scope, lazy, consider_profile,  \
 				   skip_ifunc)				      \
   do {									      \
-    int edr_lazy = (lazy);						      \
     if ((pass) != DL_RELOC_IRELATIVE)					      \
       {									      \
-	edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy),	      \
-					      (consider_profile));	      \
+	(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 ((map), (scope), edr_lazy, skip_ifunc, (pass));	      \
-    ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc, (pass));	      \
+    ELF_DYNAMIC_DO_REL ((map), (scope), (lazy), skip_ifunc, (pass));	      \
+    ELF_DYNAMIC_DO_RELA ((map), (scope), (lazy), skip_ifunc, (pass));	      \
     if ((pass) != DL_RELOC_IRELATIVE)					      \
-      ELF_DYNAMIC_AFTER_RELOC ((map), edr_lazy);			      \
+      ELF_DYNAMIC_AFTER_RELOC ((map), (lazy));				      \
   } while (0)
 
-/* Run both passes back to back, for callers with nothing to interleave.  */
+/* Run both passes back to back, for callers with nothing to interleave.
+   Unlike ELF_DYNAMIC_RELOCATE_PASS, LAZY need not be an lvalue.  */
 # define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
-  ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_ALL, (map), (scope), (lazy),	      \
-			     (consider_profile), skip_ifunc)
+  do {									      \
+    int edr_lazy = (lazy);						      \
+    ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_ALL, (map), (scope), edr_lazy,	      \
+			       (consider_profile), skip_ifunc);		      \
+  } while (0)
 
 #endif
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.