blob: 216d69121ca1d5d8497a4c44008c04a3c023c34f [file] [log] [blame]
From 5e133fc4d0f29591715a9b4558664e3631456be4 Mon Sep 17 00:00:00 2001
From: Rahul Chaudhry <rahulchaudhry@google.com>
Date: Tue, 19 Dec 2017 15:31:31 -0800
Subject: [PATCH 06/14] gold, readelf: add experimental support for SHT_RELR
sections.
This change 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. Use with caution!
This version uses the new encoding suggested by Andrew Grieve which is
described in this post on generic-abi@googlegroups.com:
https://groups.google.com/d/msg/generic-abi/bX460iggiKg/Pi9aSwwABgAJ
Bug: None
Test: 'gold --experimental-use-relr' creates PIE binaries with
'.relr.dyn' sections to store relative relocations.
[Adrian Ratiu: rebased from v2.27 to v2.35.1]
[Adrian Ratiu: squashed gold: simpler encoding for SHT_RELR sections.]
---
bfd/elf-bfd.h | 2 +-
bfd/elf.c | 27 +++-
bfd/elf32-arm.c | 1 +
bfd/elfcode.h | 2 +
bfd/elfnn-aarch64.c | 1 +
binutils/readelf.c | 126 +++++++++++++--
elfcpp/elfcpp.h | 55 +++++++
elfcpp/elfcpp_internal.h | 6 +
gold/aarch64.cc | 170 +++++++++++++++-----
gold/arm.cc | 156 ++++++++++++++----
gold/layout.cc | 14 +-
gold/layout.h | 3 +-
gold/options.h | 4 +
gold/output.cc | 51 ++++++
gold/output.h | 338 ++++++++++++++++++++++++++++++++++++++-
gold/reloc-types.h | 20 +++
gold/x86_64.cc | 183 +++++++++++++++++----
include/elf/common.h | 11 ++
include/elf/external.h | 8 +
19 files changed, 1057 insertions(+), 121 deletions(-)
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index c203e089525..5603caf9106 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -732,7 +732,7 @@ struct sym_cache
struct elf_size_info {
unsigned char sizeof_ehdr, sizeof_phdr, sizeof_shdr;
- unsigned char sizeof_rel, sizeof_rela, sizeof_sym, sizeof_dyn, sizeof_note;
+ unsigned char sizeof_rel, sizeof_rela, sizeof_relr, sizeof_sym, sizeof_dyn, sizeof_note;
/* The size of entries in the .hash section. */
unsigned char sizeof_hash_entry;
diff --git a/bfd/elf.c b/bfd/elf.c
index 9f291663992..d0c9bfa5e8b 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1748,6 +1748,9 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
case DT_RELA: name = "RELA"; break;
case DT_RELASZ: name = "RELASZ"; break;
case DT_RELAENT: name = "RELAENT"; break;
+ case DT_RELR: name = "RELR"; break;
+ case DT_RELRSZ: name = "RELRSZ"; break;
+ case DT_RELRENT: name = "RELRENT"; break;
case DT_STRSZ: name = "STRSZ"; break;
case DT_SYMENT: name = "SYMENT"; break;
case DT_INIT: name = "INIT"; break;
@@ -1785,6 +1788,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
case DT_PLTPAD: name = "PLTPAD"; break;
case DT_MOVETAB: name = "MOVETAB"; break;
case DT_SYMINFO: name = "SYMINFO"; break;
+ case DT_RELRCOUNT: name = "RELRCOUNT"; break;
case DT_RELACOUNT: name = "RELACOUNT"; break;
case DT_RELCOUNT: name = "RELCOUNT"; break;
case DT_FLAGS_1: name = "FLAGS_1"; break;
@@ -2367,16 +2371,30 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
case SHT_REL:
case SHT_RELA:
+ case SHT_RELR:
/* *These* do a lot of work -- but build no sections! */
{
asection *target_sect;
Elf_Internal_Shdr *hdr2, **p_hdr;
unsigned int num_sec = elf_numsections (abfd);
struct bfd_elf_section_data *esdt;
+ bfd_size_type size;
- if (hdr->sh_entsize
- != (bfd_size_type) (hdr->sh_type == SHT_REL
- ? bed->s->sizeof_rel : bed->s->sizeof_rela))
+ switch (hdr->sh_type)
+ {
+ case SHT_REL:
+ size = bed->s->sizeof_rel;
+ break;
+ case SHT_RELA:
+ size = bed->s->sizeof_rela;
+ break;
+ case SHT_RELR:
+ size = bed->s->sizeof_relr;
+ break;
+ default:
+ goto fail;
+ }
+ if (hdr->sh_entsize != size)
goto fail;
/* Check for a bogus link to avoid crashing. */
@@ -2446,7 +2464,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
|| hdr->sh_info == SHN_UNDEF
|| hdr->sh_info >= num_sec
|| elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL
- || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA)
+ || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA
+ || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELR)
{
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name,
shindex);
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 508f4236932..c45860a62bb 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -19855,6 +19855,7 @@ const struct elf_size_info elf32_arm_size_info =
sizeof (Elf32_External_Shdr),
sizeof (Elf32_External_Rel),
sizeof (Elf32_External_Rela),
+ sizeof (Elf32_External_Relr),
sizeof (Elf32_External_Sym),
sizeof (Elf32_External_Dyn),
sizeof (Elf_External_Note),
diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 54ef8906379..ea9cf6b4108 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -80,6 +80,7 @@
#define Elf_External_Phdr NAME(Elf,External_Phdr)
#define Elf_External_Rel NAME(Elf,External_Rel)
#define Elf_External_Rela NAME(Elf,External_Rela)
+#define Elf_External_Relr NAME(Elf,External_Relr)
#define Elf_External_Dyn NAME(Elf,External_Dyn)
#define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command)
@@ -1938,6 +1939,7 @@ const struct elf_size_info NAME(_bfd_elf,size_info) = {
sizeof (Elf_External_Shdr),
sizeof (Elf_External_Rel),
sizeof (Elf_External_Rela),
+ sizeof (Elf_External_Relr),
sizeof (Elf_External_Sym),
sizeof (Elf_External_Dyn),
sizeof (Elf_External_Note),
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 312d11b4ff9..b568565ef95 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -9925,6 +9925,7 @@ const struct elf_size_info elfNN_aarch64_size_info =
sizeof (ElfNN_External_Shdr),
sizeof (ElfNN_External_Rel),
sizeof (ElfNN_External_Rela),
+ sizeof (ElfNN_External_Relr),
sizeof (ElfNN_External_Sym),
sizeof (ElfNN_External_Dyn),
sizeof (Elf_External_Note),
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 4af4c0c6e1a..2b052c03f84 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -1138,6 +1138,80 @@ slurp_rel_relocs (Filedata * filedata,
return TRUE;
}
+static bfd_boolean
+slurp_relr_relocs (Filedata * filedata,
+ unsigned long relr_offset,
+ unsigned long relr_size,
+ Elf_Internal_Rela ** relrsp,
+ unsigned long * nrelrsp)
+{
+ Elf_Internal_Rela * relrs;
+ size_t nrelrs;
+ unsigned int i;
+
+ if (is_32bit_elf)
+ {
+ Elf32_External_Relr * erelrs;
+
+ erelrs = (Elf32_External_Relr *) get_data (NULL, filedata, relr_offset, 1,
+ relr_size, _("32-bit relocation data"));
+ if (!erelrs)
+ return FALSE;
+
+ nrelrs = relr_size / sizeof (Elf32_External_Relr);
+
+ relrs = (Elf_Internal_Rela *) cmalloc (nrelrs, sizeof (Elf_Internal_Rela));
+
+ if (relrs == NULL)
+ {
+ free (erelrs);
+ error (_("out of memory parsing relocs\n"));
+ return FALSE;
+ }
+
+ for (i = 0; i < nrelrs; i++)
+ {
+ relrs[i].r_offset = BYTE_GET (erelrs[i].r_data);
+ relrs[i].r_info = 0;
+ relrs[i].r_addend = 0;
+ }
+
+ free (erelrs);
+ }
+ else
+ {
+ Elf64_External_Relr * erelrs;
+
+ erelrs = (Elf64_External_Relr *) get_data (NULL, filedata, relr_offset, 1,
+ relr_size, _("64-bit relocation data"));
+ if (!erelrs)
+ return FALSE;
+
+ nrelrs = relr_size / sizeof (Elf64_External_Relr);
+
+ relrs = (Elf_Internal_Rela *) cmalloc (nrelrs, sizeof (Elf_Internal_Rela));
+
+ if (relrs == NULL)
+ {
+ free (erelrs);
+ error (_("out of memory parsing relocs\n"));
+ return FALSE;
+ }
+
+ for (i = 0; i < nrelrs; i++)
+ {
+ relrs[i].r_offset = BYTE_GET (erelrs[i].r_data);
+ relrs[i].r_info = 0;
+ relrs[i].r_addend = 0;
+ }
+
+ free (erelrs);
+ }
+ *relrsp = relrs;
+ *nrelrsp = nrelrs;
+ return 1;
+}
+
/* Returns the reloc type extracted from the reloc info field. */
static unsigned int
@@ -1191,6 +1265,7 @@ dump_relocations (Filedata * filedata,
char * strtab,
unsigned long strtablen,
int is_rela,
+ int is_relr,
bfd_boolean is_dynsym)
{
unsigned long i;
@@ -1205,6 +1280,11 @@ dump_relocations (Filedata * filedata,
if (!slurp_rela_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
return FALSE;
}
+ else if (is_relr)
+ {
+ if (!slurp_relr_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
+ return FALSE;
+ }
else
{
if (!slurp_rel_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
@@ -1220,6 +1300,13 @@ dump_relocations (Filedata * filedata,
else
printf (_(" Offset Info Type Sym.Value Sym. Name + Addend\n"));
}
+ else if (is_relr)
+ {
+ if (do_wide)
+ printf (_(" Data Info Type\n"));
+ else
+ printf (_(" Data Info Type\n"));
+ }
else
{
if (do_wide)
@@ -1237,6 +1324,13 @@ dump_relocations (Filedata * filedata,
else
printf (_(" Offset Info Type Sym. Value Sym. Name + Addend\n"));
}
+ else if (is_relr)
+ {
+ if (do_wide)
+ printf (_(" Data Info Type\n"));
+ else
+ printf (_(" Data Info Type\n"));
+ }
else
{
if (do_wide)
@@ -1634,7 +1728,9 @@ dump_relocations (Filedata * filedata,
break;
}
- if (rtype == NULL)
+ if (is_relr)
+ printf (do_wide ? "RELATIVE COMPRESSED" : "RELR");
+ else if (rtype == NULL)
printf (_("unrecognized: %-7lx"), (unsigned long) type & 0xffffffff);
else
printf (do_wide ? "%-22s" : "%-17.17s", rtype);
@@ -2174,6 +2270,9 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
case DT_REL: return "REL";
case DT_RELSZ: return "RELSZ";
case DT_RELENT: return "RELENT";
+ case DT_RELR: return "RELR";
+ case DT_RELRSZ: return "RELRSZ";
+ case DT_RELRENT: return "RELRENT";
case DT_PLTREL: return "PLTREL";
case DT_DEBUG: return "DEBUG";
case DT_TEXTREL: return "TEXTREL";
@@ -2211,6 +2310,7 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
case DT_TLSDESC_GOT: return "TLSDESC_GOT";
case DT_TLSDESC_PLT: return "TLSDESC_PLT";
+ case DT_RELRCOUNT: return "RELRCOUNT";
case DT_RELACOUNT: return "RELACOUNT";
case DT_RELCOUNT: return "RELCOUNT";
case DT_FLAGS_1: return "FLAGS_1";
@@ -4332,6 +4432,7 @@ get_section_type_name (Filedata * filedata, unsigned int sh_type)
case SHT_SYMTAB: return "SYMTAB";
case SHT_STRTAB: return "STRTAB";
case SHT_RELA: return "RELA";
+ case SHT_RELR: return "RELR";
case SHT_HASH: return "HASH";
case SHT_DYNAMIC: return "DYNAMIC";
case SHT_NOTE: return "NOTE";
@@ -7400,12 +7501,14 @@ static struct
int reloc;
int size;
int rela;
+ int relr;
}
dynamic_relocations [] =
{
- { "REL", DT_REL, DT_RELSZ, FALSE },
- { "RELA", DT_RELA, DT_RELASZ, TRUE },
- { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN }
+ { "REL", DT_REL, DT_RELSZ, FALSE, FALSE },
+ { "RELA", DT_RELA, DT_RELASZ, TRUE, FALSE },
+ { "RELR", DT_RELR, DT_RELRSZ, FALSE, TRUE },
+ { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN, FALSE }
};
/* Process the reloc section. */
@@ -7421,7 +7524,7 @@ process_relocs (Filedata * filedata)
if (do_using_dynamic)
{
- int is_rela;
+ int is_rela, is_relr;
const char * name;
bfd_boolean has_dynamic_reloc;
unsigned int i;
@@ -7431,6 +7534,7 @@ process_relocs (Filedata * filedata)
for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++)
{
is_rela = dynamic_relocations [i].rela;
+ is_relr = dynamic_relocations [i].relr;
name = dynamic_relocations [i].name;
rel_size = filedata->dynamic_info[dynamic_relocations [i].size];
rel_offset = filedata->dynamic_info[dynamic_relocations [i].reloc];
@@ -7465,7 +7569,7 @@ process_relocs (Filedata * filedata)
filedata->num_dynamic_syms,
filedata->dynamic_strings,
filedata->dynamic_strings_length,
- is_rela, TRUE /* is_dynamic */);
+ is_rela, is_relr, TRUE /* is_dynamic */);
}
}
@@ -7487,7 +7591,8 @@ process_relocs (Filedata * filedata)
i++, section++)
{
if ( section->sh_type != SHT_RELA
- && section->sh_type != SHT_REL)
+ && section->sh_type != SHT_REL
+ && section->sh_type != SHT_RELR)
continue;
rel_offset = section->sh_offset;
@@ -7495,7 +7600,7 @@ process_relocs (Filedata * filedata)
if (rel_size)
{
- int is_rela;
+ int is_rela, is_relr;
unsigned long num_rela;
printf (_("\nRelocation section "));
@@ -7512,6 +7617,7 @@ process_relocs (Filedata * filedata)
rel_offset, num_rela);
is_rela = section->sh_type == SHT_RELA;
+ is_relr = section->sh_type == SHT_RELR;
if (section->sh_link != 0
&& section->sh_link < filedata->file_header.e_shnum)
@@ -7533,14 +7639,14 @@ process_relocs (Filedata * filedata)
dump_relocations (filedata, rel_offset, rel_size,
symtab, nsyms, strtab, strtablen,
- is_rela,
+ is_rela, is_relr,
symsec->sh_type == SHT_DYNSYM);
free (strtab);
free (symtab);
}
else
dump_relocations (filedata, rel_offset, rel_size,
- NULL, 0, NULL, 0, is_rela,
+ NULL, 0, NULL, 0, is_rela, is_relr,
FALSE /* is_dynamic */);
found = TRUE;
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index 9c7c6294e42..9bbe4bfef86 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -386,6 +386,10 @@ enum SHT
SHT_SUNW_versym = 0x6fffffff,
SHT_GNU_versym = 0x6fffffff,
+ // Experimental support for SHT_RELR sections. For details, see proposal
+ // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ SHT_RELR = 0x6fffff00,
+
SHT_SPARC_GOTDATA = 0x70000000,
// ARM-specific section types.
@@ -765,6 +769,13 @@ enum DT
DT_VERSYM = 0x6ffffff0,
+ // Experimental support for SHT_RELR sections. For details, see proposal
+ // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ DT_RELR = 0x6fffe000,
+ DT_RELRSZ = 0x6fffe001,
+ DT_RELRENT = 0x6fffe003,
+ DT_RELRCOUNT = 0x6fffe005,
+
// Specify the value of _GLOBAL_OFFSET_TABLE_.
DT_PPC_GOT = 0x70000000,
@@ -1047,6 +1058,7 @@ struct Elf_sizes
// Sizes of ELF reloc entries.
static const int rel_size = sizeof(internal::Rel_data<size>);
static const int rela_size = sizeof(internal::Rela_data<size>);
+ static const int relr_size = sizeof(internal::Relr_data<size>);
// Size of ELF dynamic entry.
static const int dyn_size = sizeof(internal::Dyn_data<size>);
// Size of ELF version structures.
@@ -1709,6 +1721,49 @@ class Rela_write
internal::Rela_data<size>* p_;
};
+// Accessor class for an ELF Relr relocation.
+
+template<int size, bool big_endian>
+class Relr
+{
+ public:
+ Relr(const unsigned char* p)
+ : p_(reinterpret_cast<const internal::Relr_data<size>*>(p))
+ { }
+
+ template<typename File>
+ Relr(File* file, typename File::Location loc)
+ : p_(reinterpret_cast<const internal::Relr_data<size>*>(
+ file->view(loc.file_offset, loc.data_size).data()))
+ { }
+
+ typename Elf_types<size>::Elf_Addr
+ get_r_data() const
+ { return Convert<size, big_endian>::convert_host(this->p_->r_data); }
+
+ private:
+ const internal::Relr_data<size>* p_;
+};
+
+// Writer class for an ELF Relr relocation.
+
+template<int size, bool big_endian>
+class Relr_write
+{
+ public:
+ Relr_write(unsigned char* p)
+ : p_(reinterpret_cast<internal::Relr_data<size>*>(p))
+ { }
+
+ void
+ put_r_data(typename Elf_types<size>::Elf_Addr v)
+ { this->p_->r_data = Convert<size, big_endian>::convert_host(v); }
+
+ private:
+ internal::Relr_data<size>* p_;
+};
+
+
// MIPS-64 has a non-standard relocation layout.
template<bool big_endian>
diff --git a/elfcpp/elfcpp_internal.h b/elfcpp/elfcpp_internal.h
index 36a6d6205f7..0c9accaa826 100644
--- a/elfcpp/elfcpp_internal.h
+++ b/elfcpp/elfcpp_internal.h
@@ -180,6 +180,12 @@ struct Rela_data
typename Elf_types<size>::Elf_Swxword r_addend;
};
+template<int size>
+struct Relr_data
+{
+ typename Elf_types<size>::Elf_WXword r_data;
+};
+
// MIPS-64 has a non-standard layout for relocations.
struct Mips64_rel_data
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 07abe44931f..85854867cbd 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -2899,6 +2899,8 @@ class Target_aarch64 : public Sized_target<size, big_endian>
typedef Target_aarch64<size, big_endian> This;
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
Reloc_section;
+ typedef Output_data_reloc<elfcpp::SHT_RELR, true, size, big_endian>
+ Relr_section;
typedef Relocate_info<size, big_endian> The_relocate_info;
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
@@ -2920,8 +2922,8 @@ class Target_aarch64 : public Sized_target<size, big_endian>
: Sized_target<size, big_endian>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
- rela_irelative_(NULL), copy_relocs_(elfcpp::R_AARCH64_COPY),
- got_mod_index_offset_(-1U),
+ rela_irelative_(NULL), relr_dyn_(NULL),
+ copy_relocs_(elfcpp::R_AARCH64_COPY), got_mod_index_offset_(-1U),
tlsdesc_reloc_info_(), tls_base_symbol_defined_(false),
stub_tables_(), stub_group_size_(0), aarch64_input_section_map_()
{ }
@@ -3182,11 +3184,17 @@ class Target_aarch64 : public Sized_target<size, big_endian>
return this->do_make_data_plt(layout, got, got_plt, got_irelative);
}
- // We only need to generate stubs, and hence perform relaxation if we are
- // not doing relocatable linking.
virtual bool
do_may_relax() const
- { return !parameters->options().relocatable(); }
+ {
+ // If generating '.relr.dyn' section, we need a relaxation pass
+ // to do the shrinking after all the offsets have been populated.
+ if (parameters->options().experimental_use_relr())
+ return true;
+ // We need to generate stubs, and hence perform relaxation if we are
+ // not doing relocatable linking.
+ return !parameters->options().relocatable();
+ }
// Relaxation hook. This is where we do stub generation.
virtual bool
@@ -3457,6 +3465,10 @@ class Target_aarch64 : public Sized_target<size, big_endian>
Reloc_section*
rela_irelative_section(Layout*);
+ // Get the RELR dynamic reloc section, creating it if necessary.
+ Relr_section*
+ relr_dyn_section(Layout*);
+
// Add a potential copy relocation.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
@@ -3521,6 +3533,8 @@ class Target_aarch64 : public Sized_target<size, big_endian>
Reloc_section* rela_dyn_;
// The section to use for IRELATIVE relocs.
Reloc_section* rela_irelative_;
+ // The RELR dynamic reloc section.
+ Relr_section* relr_dyn_;
// Relocs saved to avoid a COPY reloc.
Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
// Offset of the GOT entry for the TLS module index.
@@ -3792,6 +3806,23 @@ Target_aarch64<size, big_endian>::rela_irelative_section(Layout* layout)
return this->rela_irelative_;
}
+// Get the RELR dynamic reloc section, creating it if necessary.
+
+template<int size, bool big_endian>
+typename Target_aarch64<size, big_endian>::Relr_section*
+Target_aarch64<size, big_endian>::relr_dyn_section(Layout* layout)
+{
+ if (this->relr_dyn_ == NULL)
+ {
+ gold_assert(layout != NULL);
+ this->relr_dyn_ = new Relr_section();
+ layout->add_output_section_data(".relr.dyn", elfcpp::SHT_RELR,
+ elfcpp::SHF_ALLOC, this->relr_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
+ }
+ return this->relr_dyn_;
+}
+
// do_make_elf_object to override the same function in the base class. We need
// to use a target-specific sub-class of Sized_relobj_file<size, big_endian> to
@@ -5642,8 +5673,34 @@ Target_aarch64<size, big_endian>::do_relax(
Layout* layout ,
const Task* task)
{
- gold_assert(!parameters->options().relocatable());
if (pass == 1)
+ {
+ Layout::Section_list::const_iterator p = layout->section_list().begin();
+ for ( ; p != layout->section_list().end(); ++p)
+ {
+ if (is_prefix_of(".relr.dyn", (*p)->name()))
+ break;
+ }
+
+ if (p != layout->section_list().end())
+ {
+ Output_section * const os = *p;
+ for (Output_section::Input_section_list::iterator ip = os->input_sections().begin();
+ ip != os->input_sections().end();
+ ++ip)
+ {
+ Relr_section *od = static_cast<Relr_section *>(ip->output_section_data());
+ od->shrink_relocs();
+ }
+ }
+
+ return true;
+ }
+
+ if (parameters->options().relocatable())
+ return false;
+
+ if (pass == 2)
{
// We don't handle negative stub_group_size right now.
this->stub_group_size_ = abs(parameters->options().stub_group_size());
@@ -5659,7 +5716,7 @@ Target_aarch64<size, big_endian>::do_relax(
}
else
{
- // If this is not the first pass, addresses and file offsets have
+ // If this is not the second pass, addresses and file offsets have
// been reset at this point, set them here.
for (Stub_table_iterator sp = this->stub_tables_.begin();
sp != this->stub_tables_.end(); ++sp)
@@ -6129,14 +6186,22 @@ Target_aarch64<size, big_endian>::Scan::local(
// reloction, so that the dynamic loader can relocate it.
if (parameters->options().output_is_position_independent())
{
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_local_relative(object, r_sym,
- elfcpp::R_AARCH64_RELATIVE,
- output_section,
- data_shndx,
- rela.get_r_offset(),
- rela.get_r_addend(),
- is_ifunc);
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn = target->relr_dyn_section(layout);
+ relr_dyn->add_local_relative(object, r_sym, output_section,
+ data_shndx, rela.get_r_offset());
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_AARCH64_RELATIVE,
+ output_section, data_shndx,
+ rela.get_r_offset(),
+ rela.get_r_addend(),
+ is_ifunc);
+ }
}
break;
@@ -6159,15 +6224,22 @@ Target_aarch64<size, big_endian>::Scan::local(
else
is_new = got->add_local(object, r_sym, GOT_TYPE_STANDARD);
if (is_new && parameters->options().output_is_position_independent())
- target->rela_dyn_section(layout)->
- add_local_relative(object,
- r_sym,
- elfcpp::R_AARCH64_RELATIVE,
- got,
- object->local_got_offset(r_sym,
- GOT_TYPE_STANDARD),
- 0,
- false);
+ {
+ unsigned int got_offset =
+ object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn = target->relr_dyn_section(layout);
+ relr_dyn->add_local_relative(object, r_sym, got, got_offset);
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_AARCH64_RELATIVE,
+ got, got_offset, 0, false);
+ }
+ }
}
break;
@@ -6448,15 +6520,25 @@ Target_aarch64<size, big_endian>::Scan::global(
else if (r_type == elfcpp::R_AARCH64_ABS64
&& gsym->can_use_relative_reloc(false))
{
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_global_relative(gsym,
- elfcpp::R_AARCH64_RELATIVE,
- output_section,
- object,
- data_shndx,
- rela.get_r_offset(),
- rela.get_r_addend(),
- false);
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn =
+ target->relr_dyn_section(layout);
+ relr_dyn->add_global_relative(gsym, output_section,
+ object, data_shndx,
+ rela.get_r_offset());
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global_relative(gsym,
+ elfcpp::R_AARCH64_RELATIVE,
+ output_section, object,
+ data_shndx,
+ rela.get_r_offset(),
+ rela.get_r_addend(),
+ false);
+ }
}
else
{
@@ -6595,12 +6677,19 @@ Target_aarch64<size, big_endian>::Scan::global(
}
if (is_new)
{
- rela_dyn->add_global_relative(
- gsym, elfcpp::R_AARCH64_RELATIVE,
- got,
- gsym->got_offset(GOT_TYPE_STANDARD),
- 0,
- false);
+ unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD);
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn =
+ target->relr_dyn_section(layout);
+ relr_dyn->add_global_relative(gsym, got, got_off);
+ }
+ else
+ {
+ rela_dyn->add_global_relative(gsym,
+ elfcpp::R_AARCH64_RELATIVE,
+ got, got_off, 0, false);
+ }
}
}
}
@@ -6950,7 +7039,8 @@ Target_aarch64<size, big_endian>::do_finalize_sections(
? NULL
: this->plt_->rela_plt());
layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
- this->rela_dyn_, true, false);
+ this->rela_dyn_, true, false,
+ this->relr_dyn_);
// Emit any relocs we saved in an attempt to avoid generating COPY
// relocs.
diff --git a/gold/arm.cc b/gold/arm.cc
index ad11c1bb007..e47b7b1278e 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -2116,6 +2116,8 @@ class Target_arm : public Sized_target<32, big_endian>
public:
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
Reloc_section;
+ typedef Output_data_reloc<elfcpp::SHT_RELR, true, 32, big_endian>
+ Relr_section;
// When were are relocating a stub, we pass this as the relocation number.
static const size_t fake_relnum_for_stubs = static_cast<size_t>(-1);
@@ -2123,7 +2125,8 @@ class Target_arm : public Sized_target<32, big_endian>
Target_arm(const Target::Target_info* info = &arm_info)
: Sized_target<32, big_endian>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
- rel_dyn_(NULL), rel_irelative_(NULL), copy_relocs_(elfcpp::R_ARM_COPY),
+ rel_dyn_(NULL), rel_irelative_(NULL), relr_dyn_(NULL),
+ copy_relocs_(elfcpp::R_ARM_COPY),
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
stub_tables_(), stub_factory_(Stub_factory::get_instance()),
should_force_pic_veneer_(false),
@@ -2519,11 +2522,17 @@ class Target_arm : public Sized_target<32, big_endian>
void
do_adjust_elf_header(unsigned char* view, int len);
- // We only need to generate stubs, and hence perform relaxation if we are
- // not doing relocatable linking.
bool
do_may_relax() const
- { return !parameters->options().relocatable(); }
+ {
+ // If generating '.relr.dyn' section, we need a relaxation pass
+ // to do the shrinking after all the offsets have been populated.
+ if (parameters->options().experimental_use_relr())
+ return true;
+ // We need to generate stubs, and hence perform relaxation if we are
+ // not doing relocatable linking.
+ return !parameters->options().relocatable();
+ }
bool
do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*);
@@ -2845,6 +2854,10 @@ class Target_arm : public Sized_target<32, big_endian>
Reloc_section*
rel_tls_desc_section(Layout*) const;
+ // Get the RELR dynamic reloc section, creating it if necessary.
+ Relr_section*
+ relr_dyn_section(Layout*);
+
// Return true if the symbol may need a COPY relocation.
// References from an executable object to non-function symbols
// defined in a dynamic object may need a COPY relocation.
@@ -3009,6 +3022,8 @@ class Target_arm : public Sized_target<32, big_endian>
Reloc_section* rel_dyn_;
// The section to use for IRELATIVE relocs.
Reloc_section* rel_irelative_;
+ // The RELR dynamic reloc section.
+ Relr_section* relr_dyn_;
// Relocs saved to avoid a COPY reloc.
Copy_relocs<elfcpp::SHT_REL, 32, big_endian> copy_relocs_;
// Offset of the GOT entry for the TLS module index.
@@ -4413,6 +4428,23 @@ Target_arm<big_endian>::rel_irelative_section(Layout* layout)
return this->rel_irelative_;
}
+// Get the RELR dynamic reloc section, creating it if necessary.
+
+template<bool big_endian>
+typename Target_arm<big_endian>::Relr_section*
+Target_arm<big_endian>::relr_dyn_section(Layout* layout)
+{
+ if (this->relr_dyn_ == NULL)
+ {
+ gold_assert(layout != NULL);
+ this->relr_dyn_ = new Relr_section();
+ layout->add_output_section_data(".relr.dyn", elfcpp::SHT_RELR,
+ elfcpp::SHF_ALLOC, this->relr_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
+ }
+ return this->relr_dyn_;
+}
+
// Insn_template methods.
@@ -8600,13 +8632,22 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
// relocate it easily.
if (parameters->options().output_is_position_independent())
{
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- // If we are to add more other reloc types than R_ARM_ABS32,
- // we need to add check_non_pic(object, r_type) here.
- rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE,
- output_section, data_shndx,
- reloc.get_r_offset(), is_ifunc);
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn = target->relr_dyn_section(layout);
+ relr_dyn->add_local_relative(object, r_sym, output_section,
+ data_shndx, reloc.get_r_offset());
+ }
+ else
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ // If we are to add more other reloc types than R_ARM_ABS32,
+ // we need to add check_non_pic(object, r_type) here.
+ rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE,
+ output_section, data_shndx,
+ reloc.get_r_offset(), is_ifunc);
+ }
}
break;
@@ -8729,11 +8770,23 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
// dynamic RELATIVE relocation for this symbol's GOT entry.
if (parameters->options().output_is_position_independent())
{
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ unsigned int got_offset =
+ object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- rel_dyn->add_local_relative(
- object, r_sym, elfcpp::R_ARM_RELATIVE, got,
- object->local_got_offset(r_sym, GOT_TYPE_STANDARD));
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn =
+ target->relr_dyn_section(layout);
+ relr_dyn->add_local_relative(object, r_sym,
+ got, got_offset);
+ }
+ else
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_ARM_RELATIVE,
+ got, got_offset);
+ }
}
}
}
@@ -9042,10 +9095,22 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
|| r_type == elfcpp::R_ARM_ABS32_NOI)
&& gsym->can_use_relative_reloc(false))
{
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE,
- output_section, object,
- data_shndx, reloc.get_r_offset());
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn =
+ target->relr_dyn_section(layout);
+ relr_dyn->add_global_relative(gsym, output_section,
+ object, data_shndx,
+ reloc.get_r_offset());
+ }
+ else
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset());
+ }
}
else
{
@@ -9212,9 +9277,21 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
gsym->set_needs_dynsym_value();
}
if (is_new)
- rel_dyn->add_global_relative(
- gsym, elfcpp::R_ARM_RELATIVE, got,
- gsym->got_offset(GOT_TYPE_STANDARD));
+ {
+ unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD);
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn =
+ target->relr_dyn_section(layout);
+ relr_dyn->add_global_relative(gsym, got, got_off);
+ }
+ else
+ {
+ rel_dyn->add_global_relative(gsym,
+ elfcpp::R_ARM_RELATIVE,
+ got, got_off);
+ }
+ }
}
}
}
@@ -9484,7 +9561,8 @@ Target_arm<big_endian>::do_finalize_sections(
? NULL
: this->plt_->rel_plt());
layout->add_target_dynamic_tags(true, this->got_plt_, rel_plt,
- this->rel_dyn_, true, false);
+ this->rel_dyn_, true, false,
+ this->relr_dyn_);
// Emit any relocs we saved in an attempt to avoid generating COPY
// relocs.
@@ -12357,14 +12435,38 @@ Target_arm<big_endian>::do_relax(
Layout* layout,
const Task* task)
{
- // No need to generate stubs if this is a relocatable link.
- gold_assert(!parameters->options().relocatable());
+ if (pass == 1)
+ {
+ Layout::Section_list::const_iterator p = layout->section_list().begin();
+ for ( ; p != layout->section_list().end(); ++p)
+ {
+ if (is_prefix_of(".relr.dyn", (*p)->name()))
+ break;
+ }
+
+ if (p != layout->section_list().end())
+ {
+ Output_section * const os = *p;
+ for (Output_section::Input_section_list::iterator ip = os->input_sections().begin();
+ ip != os->input_sections().end();
+ ++ip)
+ {
+ Relr_section *od = static_cast<Relr_section *>(ip->output_section_data());
+ od->shrink_relocs();
+ }
+ }
- // If this is the first pass, we need to group input sections into
+ return true;
+ }
+
+ if (parameters->options().relocatable())
+ return false;
+
+ // If this is the second pass, we need to group input sections into
// stub groups.
bool done_exidx_fixup = false;
typedef typename Stub_table_list::iterator Stub_table_iterator;
- if (pass == 1)
+ if (pass == 2)
{
// Determine the stub group size. The group size is the absolute
// value of the parameter --stub-group-size. If --stub-group-size
@@ -12434,7 +12536,7 @@ Target_arm<big_endian>::do_relax(
}
else
{
- // If this is not the first pass, addresses and file offsets have
+ // If this is not the second pass, addresses and file offsets have
// been reset at this point, set them here.
for (Stub_table_iterator sp = this->stub_tables_.begin();
sp != this->stub_tables_.end();
diff --git a/gold/layout.cc b/gold/layout.cc
index 13e533aaf21..723a404d6ea 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -5055,7 +5055,8 @@ void
Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got,
const Output_data* plt_rel,
const Output_data_reloc_generic* dyn_rel,
- bool add_debug, bool dynrel_includes_plt)
+ bool add_debug, bool dynrel_includes_plt,
+ const Output_data_reloc_generic* dyn_relr)
{
Output_data_dynamic* odyn = this->dynamic_data_;
if (odyn == NULL)
@@ -5128,6 +5129,17 @@ Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got,
}
}
+ if (dyn_relr != NULL && dyn_relr->output_section() != NULL)
+ {
+ const int size = parameters->target().get_size();
+ odyn->add_section_address(elfcpp::DT_RELR, dyn_relr->output_section());
+ odyn->add_section_size(elfcpp::DT_RELRSZ, dyn_relr->output_section());
+ odyn->add_constant(elfcpp::DT_RELRENT, size / 8);
+ if (parameters->options().combreloc())
+ odyn->add_constant(elfcpp::DT_RELRCOUNT,
+ dyn_relr->relative_reloc_count());
+ }
+
if (add_debug && !parameters->options().shared())
{
// The value of the DT_DEBUG tag is filled in by the dynamic
diff --git a/gold/layout.h b/gold/layout.h
index fd5878da18b..8a9d1864a67 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -945,7 +945,8 @@ class Layout
add_target_dynamic_tags(bool use_rel, const Output_data* plt_got,
const Output_data* plt_rel,
const Output_data_reloc_generic* dyn_rel,
- bool add_debug, bool dynrel_includes_plt);
+ bool add_debug, bool dynrel_includes_plt,
+ const Output_data_reloc_generic* dyn_relr = NULL);
// Add a target-specific dynamic tag with constant value.
void
diff --git a/gold/options.h b/gold/options.h
index ea379080a97..6e32d5dd6ae 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -846,6 +846,10 @@ class General_options
N_("Exclude libraries from automatic export"),
N_(("lib,lib ...")));
+ DEFINE_bool(experimental_use_relr, options::TWO_DASHES, '\0', false,
+ N_("Generate RELR dynamic relocations"),
+ N_("Do not generate RELR dynamic relocations"));
+
DEFINE_bool(export_dynamic, options::TWO_DASHES, 'E', false,
N_("Export all dynamic symbols"),
N_("Do not export all dynamic symbols"));
diff --git a/gold/output.cc b/gold/output.cc
index 75d2fc354a5..697f179097e 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -1236,6 +1236,26 @@ Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
orel.put_r_addend(addend);
}
+// Write out a Relr relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_RELR, dynamic, size, big_endian>::write(
+ unsigned char* pov) const
+{
+ elfcpp::Relr_write<size, big_endian> orel(pov);
+ if (this->bits_ == 0)
+ {
+ // This is not a continuation entry. Output full address.
+ orel.put_r_data(this->rel_.get_address());
+ }
+ else
+ {
+ // This is a continuation entry. Output the bitmap.
+ orel.put_r_data((this->bits_<<1)|1);
+ }
+}
+
// Output_data_reloc_base methods.
// Adjust the output section.
@@ -1249,6 +1269,8 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>
os->set_entsize(elfcpp::Elf_sizes<size>::rel_size);
else if (sh_type == elfcpp::SHT_RELA)
os->set_entsize(elfcpp::Elf_sizes<size>::rela_size);
+ else if (sh_type == elfcpp::SHT_RELR)
+ os->set_entsize(elfcpp::Elf_sizes<size>::relr_size);
else
gold_unreachable();
@@ -1288,6 +1310,15 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
this->do_write_generic<Writer>(of);
}
+template<bool dynamic, int size, bool big_endian>
+void
+Output_data_reloc<elfcpp::SHT_RELR, dynamic, size, big_endian>::do_write(
+ Output_file* of)
+{
+ typedef Output_reloc_writer<elfcpp::SHT_RELR, dynamic, size, big_endian> Writer;
+ this->template do_write_generic<Writer>(of);
+}
+
// Class Output_relocatable_relocs.
template<int sh_type, int size, bool big_endian>
@@ -5544,6 +5575,26 @@ template
class Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>;
#endif
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_RELR, true, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_data_reloc<elfcpp::SHT_RELR, true, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_data_reloc<elfcpp::SHT_RELR, true, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_data_reloc<elfcpp::SHT_RELR, true, 64, true>;
+#endif
+
#ifdef HAVE_TARGET_32_LITTLE
template
class Output_relocatable_relocs<elfcpp::SHT_REL, 32, false>;
diff --git a/gold/output.h b/gold/output.h
index 77b6697e067..aff10f4ab9a 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -558,7 +558,6 @@ class Output_data
void
set_current_data_size_for_child(off_t data_size)
{
- gold_assert(!this->is_data_size_valid_);
this->data_size_ = data_size;
}
@@ -1500,6 +1499,116 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
Addend addend_;
};
+// The SHT_RELR version of Output_reloc<>. This is a relative reloc,
+// and holds nothing but an offset. Rather than duplicate all the fields
+// of the SHT_REL version except for the symbol and relocation type, we
+// simply use an SHT_REL as a proxy.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_RELR, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_WXword Relr_Data;
+
+ // An uninitialized entry.
+ Output_reloc()
+ : rel_()
+ { }
+
+ // A reloc against a global symbol.
+
+ Output_reloc(Symbol* gsym, Output_data* od, Address address)
+ : rel_(gsym, 0, od, address, true, true, false),
+ bits_(0)
+ { }
+
+ Output_reloc(Symbol* gsym, Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ : rel_(gsym, 0, relobj, shndx, address, true, true, false),
+ bits_(0)
+ { }
+
+ // A reloc against a local symbol.
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, Output_data* od, Address address,
+ bool is_section_symbol)
+ : rel_(relobj, local_sym_index, 0, od, address, true,
+ true, is_section_symbol, false),
+ bits_(0)
+ { }
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int shndx,
+ Address address, bool is_section_symbol)
+ : rel_(relobj, local_sym_index, 0, shndx, address, true,
+ true, is_section_symbol, false),
+ bits_(0)
+ { }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+
+ Output_reloc(Output_section* os, Output_data* od, Address address)
+ : rel_(os, 0, od, address, true),
+ bits_(0) { }
+
+ Output_reloc(Output_section* os, Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ : rel_(os, 0, relobj, shndx, address, true),
+ bits_(0) { }
+
+ // A relative relocation with no symbol.
+
+ Output_reloc(Output_data* od, Address address)
+ : rel_(0, od, address, true),
+ bits_(0)
+ { }
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ : rel_(0, relobj, shndx, address, true),
+ bits_(0)
+ { }
+
+ // Return whether this is a RELATIVE relocation.
+ bool
+ is_relative() const
+ { return true; }
+
+ // Return whether this is a relocation which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool
+ is_symbolless() const
+ { return true; }
+
+ // If this relocation is against an input section, return the
+ // relocatable object containing the input section.
+ Sized_relobj<size, big_endian>*
+ get_relobj() const
+ { return this->rel_.get_relobj(); }
+
+ // Write the reloc entry to an output view.
+ void
+ write(unsigned char* pov) const;
+
+ // Return whether this reloc should be sorted before the argument
+ // when sorting dynamic relocs.
+ bool
+ sort_before(const Output_reloc<elfcpp::SHT_RELR, dynamic, size, big_endian>&
+ r2) const
+ { return this->rel_.compare(r2.rel_) < 0; }
+
+ public:
+ // The basic reloc.
+ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
+
+ // Relocation bitmap for encoding offsets continuing from previous entry.
+ // https://groups.google.com/d/msg/generic-abi/bX460iggiKg/Pi9aSwwABgAJ
+ // 31-bits/63-bits.
+ Relr_Data bits_;
+};
+
// Output_data_reloc_generic is a non-template base class for
// Output_data_reloc_base. This gives the generic code a way to hold
// a pointer to a reloc section.
@@ -1675,7 +1784,7 @@ class Output_data_reloc_base : public Output_data_reloc_generic
relobj->add_dyn_reloc(this->relocs_.size() - 1);
}
- private:
+ protected:
typedef std::vector<Output_reloc_type> Relocs;
// The class used to sort the relocations.
@@ -2344,6 +2453,231 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
}
};
+// The SHT_RELR version of Output_data_reloc.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_RELR, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_RELR, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_RELR, dynamic, size,
+ big_endian> Base;
+ typedef typename elfcpp::Elf_types<size>::Elf_WXword Relr_Data;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ typedef typename Base::Sort_relocs_comparison Sort_relocs_comparison;
+ typedef typename Base::Relocs Relocs;
+
+ Output_data_reloc()
+ : Output_data_reloc_base<elfcpp::SHT_RELR, dynamic, size, big_endian>(false)
+ { }
+
+ void do_write(Output_file *);
+
+ template<class Output_reloc_writer>
+ void
+ do_write_generic(Output_file *of)
+ {
+ const off_t off = this->offset();
+ const off_t oview_size = this->data_size();
+ unsigned char* const oview = of->get_output_view(off, oview_size);
+
+ unsigned char* pov = oview;
+ for (typename Relocs::const_iterator p = this->relocs_.begin();
+ p != this->relocs_.end();
+ ++p)
+ {
+ Output_reloc_writer::write(p, pov);
+ pov += Base::reloc_size;
+ }
+
+ gold_assert(pov - oview == oview_size);
+
+ of->write_output_view(off, oview_size, oview);
+
+ // We no longer need the relocation entries.
+ this->relocs_.clear();
+ }
+
+ void shrink_relocs()
+ {
+ Relocs shrink_relocs;
+ gold_assert(dynamic);
+ shrink_relocs.clear();
+
+ // Always sort the relocs_ vector for RELR relocs.
+ std::sort(this->relocs_.begin(), this->relocs_.end(),
+ Sort_relocs_comparison());
+
+ // Word size in number of bytes, used for computing the offsets bitmap.
+ unsigned int word_size = size / 8;
+
+ // Number of bits to use for the relocation offsets bitmap.
+ // These many relative relocations can be encoded in a single entry.
+ unsigned int n_bits = size - 1;
+
+ Address base = 0;
+ typename Relocs::iterator curr = this->relocs_.begin();
+ while (curr != this->relocs_.end())
+ {
+ Address current = curr->rel_.get_address();
+ // Odd addresses are not supported in SHT_RELR.
+ gold_assert(current%2 == 0);
+
+ Relr_Data bits = 0;
+ typename Relocs::iterator next = curr;
+ if ((base > 0) && (base <= current))
+ {
+ while (next != this->relocs_.end())
+ {
+ Address delta = next->rel_.get_address() - base;
+ // If next is too far out, it cannot be folded into curr.
+ if (delta >= (n_bits * word_size))
+ break;
+ // If next is not a multiple of word_size away, it cannot
+ // be folded into curr.
+ if ((delta % word_size) != 0)
+ break;
+ // next can be folded into curr, add it to the bitmap.
+ bits |= 1ULL << (delta / word_size);
+ ++next;
+ }
+ }
+
+ curr->bits_ = bits;
+ shrink_relocs.push_back(*curr);
+ if (bits == 0)
+ {
+ // This is not a continuation entry, only one offset was
+ // consumed. Set base offset for subsequent bitmap entries.
+ base = current + word_size;
+ ++curr;
+ }
+ else
+ {
+ // This is a continuation entry encoding multiple offsets
+ // in a bitmap. Advance base offset by n_bits words.
+ base += n_bits * word_size;
+ curr = next;
+ }
+ }
+
+ // Copy shrink_relocs vector to relocs_
+ this->relocs_.clear();
+ for (typename Relocs::const_iterator p = shrink_relocs.begin();
+ p != shrink_relocs.end();
+ ++p)
+ {
+ this->relocs_.push_back(*p);
+ }
+ this->set_current_data_size(this->relocs_.size() * Base::reloc_size);
+ }
+
+ void
+ add_global_generic(Symbol*, unsigned int, Output_data*, uint64_t, uint64_t)
+ {
+ gold_unreachable();
+ }
+
+ void
+ add_global_generic(Symbol*, unsigned int, Output_data*, Relobj*,
+ unsigned int, uint64_t, uint64_t)
+ {
+ gold_unreachable();
+ }
+
+ // Add a RELATIVE reloc against a global symbol. The final relocation
+ // will not reference the symbol.
+
+ void
+ add_global_relative(Symbol* gsym, Output_data* od, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, od, address));
+ }
+
+ void
+ add_global_relative(Symbol* gsym, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, relobj, shndx, address));
+ }
+
+ void
+ add_local_generic(Relobj*, unsigned int, unsigned int, Output_data*, uint64_t,
+ uint64_t)
+ {
+ gold_unreachable();
+ }
+
+ void
+ add_local_generic(Relobj*, unsigned int, unsigned int, Output_data*,
+ unsigned int, uint64_t, uint64_t)
+ {
+ gold_unreachable();
+ }
+
+ // Add a RELATIVE reloc against a local symbol.
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, Output_data* od,
+ Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, od, address,
+ false));
+ }
+
+ void
+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, Output_data* od,
+ unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, shndx, address,
+ false));
+ }
+
+ void
+ add_output_section_generic(Output_section*, unsigned int, Output_data*,
+ uint64_t, uint64_t)
+ {
+ gold_unreachable();
+ }
+
+ void
+ add_output_section_generic(Output_section*, unsigned int, Output_data*,
+ Relobj*, unsigned int, uint64_t, uint64_t)
+ {
+ gold_unreachable();
+ }
+
+ // Add a RELATIVE reloc against an output section symbol.
+
+ void
+ add_output_section_relative(Output_section* os, Output_data* od,
+ Address address)
+ { this->add(od, Output_reloc_type(os, od, address)); }
+
+ void
+ add_output_section_relative(Output_section* os, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(os, relobj, shndx, address)); }
+
+ // Add a relative relocation
+
+ void
+ add_relative(Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(od, address)); }
+
+ void
+ add_relative(Output_data* od, Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(relobj, shndx, address)); }
+};
+
// Output_relocatable_relocs represents a relocation section in a
// relocatable link. The actual data is written out in the target
// hook relocate_relocs. This just saves space for it.
diff --git a/gold/reloc-types.h b/gold/reloc-types.h
index 3671063ef0f..ee5388df6d7 100644
--- a/gold/reloc-types.h
+++ b/gold/reloc-types.h
@@ -79,6 +79,26 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
{ p->put_r_addend(val); }
};
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_RELR, size, big_endian>
+{
+ typedef typename elfcpp::Relr<size, big_endian> Reloc;
+ typedef typename elfcpp::Relr_write<size, big_endian> Reloc_write;
+ static const int reloc_size = elfcpp::Elf_sizes<size>::relr_size;
+
+ static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+ get_reloc_addend(const Reloc*)
+ { gold_unreachable(); }
+
+ static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+ get_reloc_addend_noerror(const Reloc*)
+ { return 0; }
+
+ static inline void
+ set_reloc_addend(Reloc_write*,
+ typename elfcpp::Elf_types<size>::Elf_Swxword)
+ { gold_unreachable(); }
+};
}; // End namespace gold.
#endif // !defined(GOLD_RELOC_TYPE_SH)
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 1d9d9209bf3..d4e57e84ed5 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -698,12 +698,13 @@ class Target_x86_64 : public Sized_target<size, false>
// In the x86_64 ABI (p 68), it says "The AMD64 ABI architectures
// uses only Elf64_Rela relocation entries with explicit addends."
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
+ typedef Output_data_reloc<elfcpp::SHT_RELR, true, size, false> Relr_section;
Target_x86_64(const Target::Target_info* info = &x86_64_info)
: Sized_target<size, false>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
- rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY),
+ rela_irelative_(NULL), relr_dyn_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY),
got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
tls_base_symbol_defined_(false), isa_1_used_(0), isa_1_needed_(0),
feature_1_(0), object_isa_1_used_(0), object_feature_1_(0),
@@ -982,6 +983,43 @@ class Target_x86_64 : public Sized_target<size, false>
Output_data_space* got_irelative,
unsigned int plt_count);
+ bool
+ do_may_relax() const
+ {
+ // If generating '.relr.dyn' section, we need a relaxation pass
+ // to do the shrinking after all the offsets have been populated.
+ return parameters->options().experimental_use_relr();
+ }
+
+ bool
+ do_relax (int pass, const Input_objects*, Symbol_table*, Layout* layout, const Task*)
+ {
+ if (pass > 1)
+ return false;
+
+ Layout::Section_list::const_iterator p = layout->section_list().begin();
+ for ( ; p != layout->section_list().end(); ++p)
+ {
+ if (is_prefix_of(".relr.dyn", (*p)->name()))
+ break;
+ }
+
+ if (p == layout->section_list().end())
+ return false;
+
+ Output_section * const os = *p;
+ for (Output_section::Input_section_list::iterator ip = os->input_sections().begin();
+ ip != os->input_sections().end();
+ ++ip)
+ {
+ Relr_section *od = static_cast<Relr_section *>(ip->output_section_data());
+ od->shrink_relocs();
+ }
+
+ return true;
+ }
+
+
private:
// The class which scans relocations.
class Scan
@@ -1289,6 +1327,10 @@ class Target_x86_64 : public Sized_target<size, false>
Reloc_section*
rela_irelative_section(Layout*);
+ // Get the RELR dynamic reloc section, creating it if necessary.
+ Relr_section*
+ relr_dyn_section(Layout*);
+
// Add a potential copy relocation.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
@@ -1367,6 +1409,8 @@ class Target_x86_64 : public Sized_target<size, false>
Reloc_section* rela_dyn_;
// The section to use for IRELATIVE relocs.
Reloc_section* rela_irelative_;
+ // The RELR dynamic reloc section.
+ Relr_section* relr_dyn_;
// Relocs saved to avoid a COPY reloc.
Copy_relocs<elfcpp::SHT_RELA, size, false> copy_relocs_;
// Offset of the GOT entry for the TLS module index.
@@ -1678,6 +1722,23 @@ Target_x86_64<size>::do_finalize_gnu_properties(Layout* layout) const
this->feature_1_);
}
+// Get the RELR dynamic reloc section, creating it if necessary.
+
+template<int size>
+typename Target_x86_64<size>::Relr_section*
+Target_x86_64<size>::relr_dyn_section(Layout* layout)
+{
+ if (this->relr_dyn_ == NULL)
+ {
+ gold_assert(layout != NULL);
+ this->relr_dyn_ = new Relr_section();
+ layout->add_output_section_data(".relr.dyn", elfcpp::SHT_RELR,
+ elfcpp::SHF_ALLOC, this->relr_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
+ }
+ return this->relr_dyn_;
+}
+
// Write the first three reserved words of the .got.plt section.
// The remainder of the section is written while writing the PLT
// in Output_data_plt_i386::do_write.
@@ -3596,14 +3657,25 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab,
if (parameters->options().output_is_position_independent())
{
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_local_relative(object, r_sym,
- (size == 32
- ? elfcpp::R_X86_64_RELATIVE64
- : elfcpp::R_X86_64_RELATIVE),
- output_section, data_shndx,
- reloc.get_r_offset(),
- reloc.get_r_addend(), is_ifunc);
+ if (size == 64
+ && !is_ifunc
+ && parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn = target->relr_dyn_section(layout);
+ relr_dyn->add_local_relative(object, r_sym, output_section,
+ data_shndx, reloc.get_r_offset());
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_local_relative(object, r_sym,
+ (size == 32
+ ? elfcpp::R_X86_64_RELATIVE64
+ : elfcpp::R_X86_64_RELATIVE),
+ output_section, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), is_ifunc);
+ }
}
break;
@@ -3621,12 +3693,22 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab,
if (size == 32 && r_type == elfcpp::R_X86_64_32)
{
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_local_relative(object, r_sym,
- elfcpp::R_X86_64_RELATIVE,
- output_section, data_shndx,
- reloc.get_r_offset(),
- reloc.get_r_addend(), is_ifunc);
+ if (!is_ifunc && parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn = target->relr_dyn_section(layout);
+ relr_dyn->add_local_relative(object, r_sym, output_section,
+ data_shndx,
+ reloc.get_r_offset());
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_X86_64_RELATIVE,
+ output_section, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), is_ifunc);
+ }
break;
}
@@ -3727,24 +3809,33 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab,
// dynamic relocation for this symbol's GOT entry.
if (parameters->options().output_is_position_independent())
{
+ unsigned int got_offset =
+ object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
// R_X86_64_RELATIVE assumes a 64-bit relocation.
- if (r_type != elfcpp::R_X86_64_GOT32)
- {
- unsigned int got_offset =
- object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
- rela_dyn->add_local_relative(object, r_sym,
- elfcpp::R_X86_64_RELATIVE,
- got, got_offset, 0, is_ifunc);
- }
- else
+ if (r_type == elfcpp::R_X86_64_GOT32)
{
this->check_non_pic(object, r_type, NULL);
gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
rela_dyn->add_local(
object, r_sym, r_type, got,
- object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0);
+ got_offset, 0);
+ }
+ else if (size == 64
+ && !is_ifunc
+ && parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn =
+ target->relr_dyn_section(layout);
+ relr_dyn->add_local_relative(object, r_sym,
+ got, got_offset);
+ }
+ else
+ {
+ rela_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_X86_64_RELATIVE,
+ got, got_offset, 0, is_ifunc);
}
}
}
@@ -4108,12 +4199,24 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
|| (size == 32 && r_type == elfcpp::R_X86_64_32))
&& gsym->can_use_relative_reloc(false))
{
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE,
- output_section, object,
- data_shndx,
- reloc.get_r_offset(),
- reloc.get_r_addend(), false);
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn =
+ target->relr_dyn_section(layout);
+ relr_dyn->add_global_relative(gsym, output_section,
+ object, data_shndx,
+ reloc.get_r_offset());
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global_relative(gsym,
+ elfcpp::R_X86_64_RELATIVE,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend(), false);
+ }
}
else
{
@@ -4251,9 +4354,18 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
if (is_new)
{
unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD);
- rela_dyn->add_global_relative(gsym,
- elfcpp::R_X86_64_RELATIVE,
- got, got_off, 0, false);
+ if (parameters->options().experimental_use_relr())
+ {
+ Relr_section* relr_dyn =
+ target->relr_dyn_section(layout);
+ relr_dyn->add_global_relative(gsym, got, got_off);
+ }
+ else
+ {
+ rela_dyn->add_global_relative(gsym,
+ elfcpp::R_X86_64_RELATIVE,
+ got, got_off, 0, false);
+ }
}
}
}
@@ -4522,7 +4634,8 @@ Target_x86_64<size>::do_finalize_sections(
? NULL
: this->plt_->rela_plt());
layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
- this->rela_dyn_, true, false);
+ this->rela_dyn_, true, false,
+ this->relr_dyn_);
// Fill in some more dynamic tags.
Output_data_dynamic* const odyn = layout->dynamic_data();
diff --git a/include/elf/common.h b/include/elf/common.h
index 4d94c4fd5b3..83374777d20 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -526,6 +526,10 @@
#define SHT_GNU_verneed SHT_SUNW_verneed
#define SHT_GNU_versym SHT_SUNW_versym
+/* Experimental support for SHT_RELR sections. For details, see proposal
+ at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg */
+#define SHT_RELR 0x6fffff00 /* Relative relocations, only offsets */
+
#define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */
#define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */
#define SHT_LOUSER 0x80000000 /* Application-specific semantics */
@@ -1041,6 +1045,13 @@
/* This tag is a GNU extension to the Solaris version scheme. */
#define DT_VERSYM 0x6ffffff0
+/* Experimental support for SHT_RELR sections. For details, see proposal
+ at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg */
+#define DT_RELR 0x6fffe000
+#define DT_RELRSZ 0x6fffe001
+#define DT_RELRENT 0x6fffe003
+#define DT_RELRCOUNT 0x6fffe005
+
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
diff --git a/include/elf/external.h b/include/elf/external.h
index 230fdabd87a..6a43ebe9daf 100644
--- a/include/elf/external.h
+++ b/include/elf/external.h
@@ -211,6 +211,10 @@ typedef struct {
unsigned char r_addend[4]; /* Constant addend used to compute value */
} Elf32_External_Rela;
+typedef struct {
+ unsigned char r_data[4]; /* jump and bitmap for relative relocations */
+} Elf32_External_Relr;
+
typedef struct {
unsigned char r_offset[8]; /* Location at which to apply the action */
unsigned char r_info[8]; /* index and type of relocation */
@@ -222,6 +226,10 @@ typedef struct {
unsigned char r_addend[8]; /* Constant addend used to compute value */
} Elf64_External_Rela;
+typedef struct {
+ unsigned char r_data[8]; /* jump and bitmap for relative relocations */
+} Elf64_External_Relr;
+
/* dynamic section structure */
typedef struct {
--
2.31.1