diff options
author | Fangrui Song <maskray@google.com> | 2022-03-08 17:17:05 -0800 |
---|---|---|
committer | Fangrui Song <maskray@google.com> | 2022-03-08 17:17:05 -0800 |
commit | 1c6cc29baf9a4c7129ab2e94b0d4022bfa4f3299 (patch) | |
tree | 008312335cd84ecfcc73c38b72ba836d06e3ca2f /elf/dynamic-link.h | |
parent | edc696a73a7cb07b1aa68792a845a98d036ee7eb (diff) | |
download | glibc-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.h | 34 |
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) |