summaryrefslogtreecommitdiff
path: root/elf/dynamic-link.h
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dynamic-link.h')
-rw-r--r--elf/dynamic-link.h34
1 files changed, 34 insertions, 0 deletions
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 25dd7ca4f2..169745f9a4 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -146,12 +146,46 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) /* Nothing to do. */
# endif
+# define ELF_DYNAMIC_DO_RELR(map) \
+ do { \
+ ElfW(Addr) l_addr = (map)->l_addr, *where = 0; \
+ const ElfW(Relr) *r, *end; \
+ if (!(map)->l_info[DT_RELR]) \
+ break; \
+ r = (const ElfW(Relr) *)D_PTR((map), l_info[DT_RELR]); \
+ end = (const ElfW(Relr) *)((const char *)r + \
+ (map)->l_info[DT_RELRSZ]->d_un.d_val); \
+ for (; r < end; r++) \
+ { \
+ ElfW(Relr) entry = *r; \
+ if ((entry & 1) == 0) \
+ { \
+ where = (ElfW(Addr) *)(l_addr + entry); \
+ *where++ += l_addr; \
+ } \
+ else \
+ { \
+ for (long i = 0; (entry >>= 1) != 0; i++) \
+ if ((entry & 1) != 0) \
+ where[i] += l_addr; \
+ where += CHAR_BIT * sizeof(ElfW(Relr)) - 1; \
+ } \
+ } \
+ } while (0);
+
/* This can't just be an inline function because GCC is too dumb
to inline functions containing inlines themselves. */
+# ifdef RTLD_BOOTSTRAP
+# define DO_RTLD_BOOTSTRAP 1
+# else
+# define DO_RTLD_BOOTSTRAP 0
+# endif
# define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
do { \
int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
(consider_profile)); \
+ if ((map) != &GL(dl_rtld_map) || DO_RTLD_BOOTSTRAP) \
+ ELF_DYNAMIC_DO_RELR (map); \
ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \
ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc); \
} while (0)