aboutsummaryrefslogtreecommitdiff
path: root/elf/dynamic-link.h
diff options
context:
space:
mode:
authorFangrui Song <maskray@google.com>2022-03-08 17:17:05 -0800
committerFangrui Song <maskray@google.com>2022-03-08 17:17:05 -0800
commit1c6cc29baf9a4c7129ab2e94b0d4022bfa4f3299 (patch)
tree008312335cd84ecfcc73c38b72ba836d06e3ca2f /elf/dynamic-link.h
parentedc696a73a7cb07b1aa68792a845a98d036ee7eb (diff)
downloadglibc-maskray/relr.tar
glibc-maskray/relr.tar.gz
glibc-maskray/relr.tar.bz2
glibc-maskray/relr.zip
elf: Support DT_RELR relative relocation format [BZ #27924]maskray/relr
PIE and shared objects usually have many relative relocations. In 2017/2018, SHT_RELR/DT_RELR was proposed on https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/GxjM0L-PBAAJ ("Proposal for a new section type SHT_RELR") and is a pre-standard. RELR usually takes 3% or smaller space than R_*_RELATIVE relocations. The virtual memory size of a mostly statically linked PIE is typically 5~10% smaller. This patch adds ELF_DYNAMIC_DO_RELR to ELF_DYNAMIC_RELOCATE. ELF_DYNAMIC_DO_RELR is ordered before ELF_DYNAMIC_DO_REL[A] so that ifunc resolvers that require relocated got entries have them relocated. This is needed for ppc64 according to Alan Modra.
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)