blob: 00b315697e324424686fdefed0c2ac8ec851067a [file] [log] [blame]
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