[PATCH v2 2/2] elf: Use the effective lazy mode for the deferred IRELATIVE pass
Adhemerval Zanella <[email protected]> Mon, 3 Aug 2026 11:02:54 -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 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.
---
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 5dc5a545a8d..a3d984f6020 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 fa2f41ac445..bed0c4f844a 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -278,7 +278,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
@@ -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_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 0130c63feb1..81a3f0856e0 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
--
2.53.0