| From 6676e967dba405ca31d57b63e096becd13d4a200 Mon Sep 17 00:00:00 2001 |
| From: Rahul Chaudhry <rahulchaudhry@chromium.org> |
| Date: Thu, 15 Mar 2018 14:30:17 -0700 |
| Subject: [PATCH 4/8] sys-libs/glibc: add support for SHT_RELR sections. |
| |
| This patch adds experimental support for SHT_RELR sections, proposed |
| here: https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg |
| |
| SHT_RELR sections are supported for arm, aarch64, and x86_64 targets. |
| To enable them, pass '--experimental-use-relr' flag to gold. |
| |
| Definitions for the new ELF section type and dynamic array tags, as well |
| as the encoding used in the new section are all under discussion and are |
| subject to change. We plan to send the patch upstream after the gABI has |
| been updated to include the new definitions. |
| |
| [Adrian: forward-ported to glibc 2.32] |
| --- |
| elf/do-rel.h | 41 ++++++++++++++++++++++++++++++++++-- |
| elf/dynamic-link.h | 15 +++++++++++++ |
| elf/elf.h | 15 +++++++++++-- |
| elf/get-dynamic-info.h | 7 ++++++ |
| sysdeps/aarch64/dl-machine.h | 10 +++++++++ |
| sysdeps/arm/dl-machine.h | 10 +++++++++ |
| sysdeps/i386/dl-machine.h | 10 +++++++++ |
| sysdeps/x86_64/dl-machine.h | 10 +++++++++ |
| 8 files changed, 114 insertions(+), 4 deletions(-) |
| |
| diff --git a/elf/do-rel.h b/elf/do-rel.h |
| index 1d0a1f2c5d..25babef6e1 100644 |
| --- a/elf/do-rel.h |
| +++ b/elf/do-rel.h |
| @@ -26,6 +26,12 @@ |
| # define elf_machine_rel_relative elf_machine_rela_relative |
| #endif |
| |
| +#ifdef DO_RELR |
| +# define elf_dynamic_do_Rel elf_dynamic_do_Relr |
| +# define Rel Relr |
| +# define elf_machine_rel_relative elf_machine_relr_relative |
| +#endif |
| + |
| #ifndef DO_ELF_MACHINE_REL_RELATIVE |
| # define DO_ELF_MACHINE_REL_RELATIVE(map, l_addr, relative) \ |
| elf_machine_rel_relative (l_addr, relative, \ |
| @@ -46,12 +52,12 @@ elf_dynamic_do_Rel (struct link_map *map, |
| const ElfW(Rel) *r = (const void *) reladdr; |
| const ElfW(Rel) *end = (const void *) (reladdr + relsize); |
| ElfW(Addr) l_addr = map->l_addr; |
| -# if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP |
| +# if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP && !defined DO_RELR |
| const ElfW(Rel) *r2 = NULL; |
| const ElfW(Rel) *end2 = NULL; |
| # endif |
| |
| -#if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP |
| +#if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP && !defined DO_RELR |
| /* We never bind lazily during ld.so bootstrap. Unfortunately gcc is |
| not clever enough to see through all the function calls to realize |
| that. */ |
| @@ -80,8 +86,10 @@ elf_dynamic_do_Rel (struct link_map *map, |
| else |
| #endif |
| { |
| +# if !defined DO_RELR |
| const ElfW(Sym) *const symtab = |
| (const void *) D_PTR (map, l_info[DT_SYMTAB]); |
| +# endif |
| const ElfW(Rel) *relative = r; |
| r += nrelative; |
| |
| @@ -108,9 +116,36 @@ elf_dynamic_do_Rel (struct link_map *map, |
| if (l_addr != 0 || ! map->l_info[VALIDX(DT_GNU_PRELINKED)]) |
| # endif |
| #endif |
| + |
| +#ifdef DO_RELR |
| + { |
| + ElfW(Addr) base = 0; |
| + for (; relative < end; ++relative) |
| + { |
| + ElfW(Relr) entry = *relative; |
| + if ((entry&1) == 0) |
| + { |
| + elf_machine_relr_relative (l_addr, (void *) (l_addr + entry)); |
| + base = entry + sizeof(ElfW(Addr)); |
| + continue; |
| + } |
| + ElfW(Addr) offset = base; |
| + while (entry != 0) |
| + { |
| + entry >>= 1; |
| + if ((entry&1) != 0) |
| + elf_machine_relr_relative (l_addr, (void *) (l_addr + offset)); |
| + offset += sizeof(ElfW(Addr)); |
| + } |
| + base += (8*sizeof(ElfW(Addr)) - 1) * sizeof(ElfW(Addr)); |
| + } |
| + } |
| +#else |
| for (; relative < r; ++relative) |
| DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative); |
| +#endif |
| |
| +#if !defined DO_RELR |
| #ifdef RTLD_BOOTSTRAP |
| /* The dynamic linker always uses versioning. */ |
| assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL); |
| @@ -179,6 +214,7 @@ elf_dynamic_do_Rel (struct link_map *map, |
| skip_ifunc); |
| # endif |
| } |
| +#endif |
| #endif |
| } |
| } |
| @@ -189,3 +225,4 @@ elf_dynamic_do_Rel (struct link_map *map, |
| #undef elf_machine_rel_relative |
| #undef DO_ELF_MACHINE_REL_RELATIVE |
| #undef DO_RELA |
| +#undef DO_RELR |
| diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h |
| index 6727233e1a..4345df9949 100644 |
| --- a/elf/dynamic-link.h |
| +++ b/elf/dynamic-link.h |
| @@ -76,6 +76,11 @@ auto inline void __attribute__((always_inline)) |
| elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc, |
| void *const reloc_addr); |
| # endif |
| +# if ! ELF_MACHINE_NO_RELR |
| +auto inline void __attribute__((always_inline)) |
| +elf_machine_relr_relative (ElfW(Addr) l_addr, |
| + void *const reloc_addr); |
| +# endif |
| # if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL |
| auto inline void __attribute__((always_inline)) |
| elf_machine_lazy_rel (struct link_map *map, |
| @@ -190,6 +195,15 @@ elf_machine_lazy_rel (struct link_map *map, |
| # define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) /* Nothing to do. */ |
| # endif |
| |
| +# if ! ELF_MACHINE_NO_RELR |
| +# define DO_RELR |
| +# include "do-rel.h" |
| +# define ELF_DYNAMIC_DO_RELR(map, lazy, skip_ifunc) \ |
| + _ELF_DYNAMIC_DO_RELOC (RELR, Relr, map, lazy, skip_ifunc, 1) |
| +# else |
| +# define ELF_DYNAMIC_DO_RELR(map, lazy, skip_ifunc) /* Nothing to do. */ |
| +# endif |
| + |
| /* This can't just be an inline function because GCC is too dumb |
| to inline functions containing inlines themselves. */ |
| # define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile, skip_ifunc) \ |
| @@ -198,6 +212,7 @@ elf_machine_lazy_rel (struct link_map *map, |
| (consider_profile)); \ |
| ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc); \ |
| ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc); \ |
| + ELF_DYNAMIC_DO_RELR ((map), edr_lazy, skip_ifunc); \ |
| } while (0) |
| |
| #endif |
| diff --git a/elf/elf.h b/elf/elf.h |
| index 197b557d15..5b6da8e8ae 100644 |
| --- a/elf/elf.h |
| +++ b/elf/elf.h |
| @@ -446,7 +446,8 @@ typedef struct |
| #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ |
| #define SHT_GROUP 17 /* Section group */ |
| #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ |
| -#define SHT_NUM 19 /* Number of defined types. */ |
| +#define SHT_RELR 19 /* Relative relocation, only offsets */ |
| +#define SHT_NUM 20 /* Number of defined types. */ |
| #define SHT_LOOS 0x60000000 /* Start OS-specific. */ |
| #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ |
| #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ |
| @@ -664,6 +665,12 @@ typedef struct |
| Elf64_Sxword r_addend; /* Addend */ |
| } Elf64_Rela; |
| |
| +/* Relocation table entry for relative (in section of type SHT_RELR). */ |
| + |
| +typedef Elf32_Word Elf32_Relr; /* offset/bitmap for relative relocations */ |
| + |
| +typedef Elf64_Xword Elf64_Relr; /* offset/bitmap for relative relocations */ |
| + |
| /* How to extract and insert information held in the r_info field. */ |
| |
| #define ELF32_R_SYM(val) ((val) >> 8) |
| @@ -885,7 +892,10 @@ typedef struct |
| #define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ |
| #define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ |
| #define DT_SYMTAB_SHNDX 34 /* Address of SYMTAB_SHNDX section */ |
| -#define DT_NUM 35 /* Number used */ |
| +#define DT_RELRSZ 35 |
| +#define DT_RELR 36 |
| +#define DT_RELRENT 37 |
| +#define DT_NUM 38 /* Number used */ |
| #define DT_LOOS 0x6000000d /* Start of OS-specific */ |
| #define DT_HIOS 0x6ffff000 /* End of OS-specific */ |
| #define DT_LOPROC 0x70000000 /* Start of processor-specific */ |
| @@ -937,6 +947,7 @@ typedef struct |
| GNU extension. */ |
| #define DT_VERSYM 0x6ffffff0 |
| |
| +#define DT_RELRCOUNT 0x6ffffff8 |
| #define DT_RELACOUNT 0x6ffffff9 |
| #define DT_RELCOUNT 0x6ffffffa |
| |
| diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h |
| index 4f6a86ef37..79ff22f0c0 100644 |
| --- a/elf/get-dynamic-info.h |
| +++ b/elf/get-dynamic-info.h |
| @@ -108,6 +108,9 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) |
| # if ! ELF_MACHINE_NO_REL |
| ADJUST_DYN_INFO (DT_REL); |
| # endif |
| +# if ! ELF_MACHINE_NO_RELR |
| + ADJUST_DYN_INFO (DT_RELR); |
| +#endif |
| ADJUST_DYN_INFO (DT_JMPREL); |
| ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); |
| ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH)); |
| @@ -134,6 +137,10 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) |
| if (info[DT_REL] != NULL) |
| assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); |
| #endif |
| +#if ! ELF_MACHINE_NO_RELR |
| + if (info[DT_RELR] != NULL) |
| + assert (info[DT_RELRENT]->d_un.d_val == sizeof (ElfW(Relr))); |
| +# endif |
| #ifdef RTLD_BOOTSTRAP |
| /* Only the bind now flags are allowed. */ |
| assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL |
| diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h |
| index fde7cfd9e2..eaff6dbc6d 100644 |
| --- a/sysdeps/aarch64/dl-machine.h |
| +++ b/sysdeps/aarch64/dl-machine.h |
| @@ -198,6 +198,7 @@ _dl_start_user: \n\ |
| /* AArch64 uses RELA not REL */ |
| #define ELF_MACHINE_NO_REL 1 |
| #define ELF_MACHINE_NO_RELA 0 |
| +#define ELF_MACHINE_NO_RELR 0 |
| |
| #define DL_PLATFORM_INIT dl_platform_init () |
| |
| @@ -383,6 +384,15 @@ elf_machine_rela_relative (ElfW(Addr) l_addr, |
| *reloc_addr = l_addr + reloc->r_addend; |
| } |
| |
| +inline void |
| +__attribute__ ((always_inline)) |
| +elf_machine_relr_relative (ElfW(Addr) l_addr, |
| + void *const reloc_addr_arg) |
| +{ |
| + ElfW(Addr) *const reloc_addr = reloc_addr_arg; |
| + *reloc_addr += l_addr; |
| +} |
| + |
| inline void |
| __attribute__ ((always_inline)) |
| elf_machine_lazy_rel (struct link_map *map, |
| diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h |
| index 90856779b1..c586232c9d 100644 |
| --- a/sysdeps/arm/dl-machine.h |
| +++ b/sysdeps/arm/dl-machine.h |
| @@ -296,6 +296,7 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc, |
| Prelinked libraries may use Elf32_Rela though. */ |
| #define ELF_MACHINE_NO_RELA defined RTLD_BOOTSTRAP |
| #define ELF_MACHINE_NO_REL 0 |
| +#define ELF_MACHINE_NO_RELR 0 |
| |
| /* Names of the architecture-specific auditing callback functions. */ |
| #define ARCH_LA_PLTENTER arm_gnu_pltenter |
| @@ -637,6 +638,15 @@ elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc, |
| *reloc_addr += l_addr; |
| } |
| |
| +auto inline void |
| +__attribute ((always_inline)) |
| +elf_machine_relr_relative (ElfW(Addr) l_addr, |
| + void *const reloc_addr_arg) |
| +{ |
| + ElfW(Addr) *const reloc_addr = reloc_addr_arg; |
| + *reloc_addr += l_addr; |
| +} |
| + |
| # ifndef RTLD_BOOTSTRAP |
| auto inline void |
| __attribute__ ((always_inline)) |
| diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h |
| index 672d8f27ce..7c09608913 100644 |
| --- a/sysdeps/i386/dl-machine.h |
| +++ b/sysdeps/i386/dl-machine.h |
| @@ -286,6 +286,7 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc, |
| Prelinked libraries may use Elf32_Rela though. */ |
| #define ELF_MACHINE_NO_RELA defined RTLD_BOOTSTRAP |
| #define ELF_MACHINE_NO_REL 0 |
| +#define ELF_MACHINE_NO_RELR 0 |
| |
| #ifdef RESOLVE_MAP |
| |
| @@ -658,6 +659,15 @@ elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc, |
| *reloc_addr += l_addr; |
| } |
| |
| +auto inline void |
| +__attribute ((always_inline)) |
| +elf_machine_relr_relative (ElfW(Addr) l_addr, |
| + void *const reloc_addr_arg) |
| +{ |
| + ElfW(Addr) *const reloc_addr = reloc_addr_arg; |
| + *reloc_addr += l_addr; |
| +} |
| + |
| # ifndef RTLD_BOOTSTRAP |
| auto inline void |
| __attribute__ ((always_inline)) |
| diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h |
| index 363a749cb2..10a200ba67 100644 |
| --- a/sysdeps/x86_64/dl-machine.h |
| +++ b/sysdeps/x86_64/dl-machine.h |
| @@ -214,6 +214,7 @@ _dl_start_user:\n\ |
| /* The x86-64 never uses Elf64_Rel/Elf32_Rel relocations. */ |
| #define ELF_MACHINE_NO_REL 1 |
| #define ELF_MACHINE_NO_RELA 0 |
| +#define ELF_MACHINE_NO_RELR 0 |
| |
| /* We define an initialization function. This is called very early in |
| _dl_sysdep_start. */ |
| @@ -549,6 +550,15 @@ elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc, |
| } |
| } |
| |
| +auto inline void |
| +__attribute ((always_inline)) |
| +elf_machine_relr_relative (ElfW(Addr) l_addr, |
| + void *const reloc_addr_arg) |
| +{ |
| + ElfW(Addr) *const reloc_addr = reloc_addr_arg; |
| + *reloc_addr += l_addr; |
| +} |
| + |
| auto inline void |
| __attribute ((always_inline)) |
| elf_machine_lazy_rel (struct link_map *map, |
| -- |
| 2.30.2 |
| |