Experimental implementation of RELR-style relocations.

For x86-64 only. Instead of R_X86_64_RELATIVE relocations, we
write the offsets of the relocation targets to a new section,
.relr.dyn, with section type SHT_RELR.
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index cce40d4..d4c0a63 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -358,6 +358,7 @@
   SHT_PREINIT_ARRAY = 16,
   SHT_GROUP = 17,
   SHT_SYMTAB_SHNDX = 18,
+  SHT_RELR = 19,		// Experimental
   SHT_LOOS = 0x60000000,
   SHT_HIOS = 0x6fffffff,
   SHT_LOPROC = 0x70000000,
@@ -719,6 +720,11 @@
 
   DT_PREINIT_ARRAY = 32,
   DT_PREINIT_ARRAYSZ = 33,
+  DT_SYMTAB_SHNDX = 34,
+  DT_RELRSZ = 35,		// Experimental
+  DT_RELR = 36,			// Experimental
+  DT_RELRENT = 37,		// Experimental
+
   DT_LOOS = 0x6000000d,
   DT_HIOS = 0x6ffff000,
   DT_LOPROC = 0x70000000,
@@ -1021,6 +1027,7 @@
   // 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.
@@ -1666,6 +1673,48 @@
   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_offset() const
+  { return Convert<size, big_endian>::convert_host(this->p_->r_offset); }
+
+ 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_offset(typename Elf_types<size>::Elf_Addr v)
+  { this->p_->r_offset = 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 14adfde..a1cfcf5 100644
--- a/elfcpp/elfcpp_internal.h
+++ b/elfcpp/elfcpp_internal.h
@@ -180,6 +180,12 @@
   typename Elf_types<size>::Elf_Swxword r_addend;
 };
 
+template<int size>
+struct Relr_data
+{
+  typename Elf_types<size>::Elf_Addr r_offset;
+};
+
 // MIPS-64 has a non-standard layout for relocations.
 
 struct Mips64_rel_data
diff --git a/gold/layout.cc b/gold/layout.cc
index 07a3590..504028a 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -4710,7 +4710,8 @@
 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)
@@ -4783,6 +4784,14 @@
 	}
     }
 
+  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 (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 5f58c2c..5852898 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -900,7 +900,8 @@
   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 a8b1d46..b08acad 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -834,6 +834,10 @@
 		 N_("Exclude libraries from automatic export"),
 		 N_(("lib,lib ...")));
 
+  DEFINE_bool(experimental_use_relr, options::TWO_DASHES, '\0', false,
+	      N_("(x86-64 only) 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 5b1e601..8c27ad4 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -1224,6 +1224,17 @@
   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);
+  orel.put_r_offset(this->rel_.get_address());
+}
+
 // Output_data_reloc_base methods.
 
 // Adjust the output section.
@@ -1237,6 +1248,8 @@
     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();
 
@@ -5528,6 +5541,26 @@
 
 #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>;
 #endif
 
diff --git a/gold/output.h b/gold/output.h
index 157cef2..f33a7f8 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -1500,6 +1500,104 @@
   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;
+
+  // 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)
+  { }
+
+  Output_reloc(Symbol* gsym, Sized_relobj<size, big_endian>* relobj,
+	       unsigned int shndx, Address address)
+    : rel_(gsym, 0, relobj, shndx, address, true, true, false)
+  { }
+
+  // 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)
+  { }
+
+  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)
+  { }
+
+  // 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)
+  { }
+
+  Output_reloc(Output_section* os, Sized_relobj<size, big_endian>* relobj,
+	       unsigned int shndx, Address address)
+    : rel_(os, 0, relobj, shndx, address, true)
+  { }
+
+  // A relative relocation with no symbol.
+
+  Output_reloc(Output_data* od, Address address)
+    : rel_(0, od, address, true)
+  { }
+
+  Output_reloc(Sized_relobj<size, big_endian>* relobj,
+	       unsigned int shndx, Address address)
+    : rel_(0, relobj, shndx, address, true)
+  { }
+
+  // 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; }
+
+ private:
+  // The basic reloc.
+  Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
+};
+
 // 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.
@@ -2344,6 +2442,127 @@
   }
 };
 
+// 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;
+
+ public:
+  typedef typename Base::Output_reloc_type Output_reloc_type;
+  typedef typename Output_reloc_type::Address Address;
+
+  Output_data_reloc()
+    : Output_data_reloc_base<elfcpp::SHT_RELR, dynamic, size, big_endian>(false)
+  { }
+
+  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 eea7dd6..f25cd5b 100644
--- a/gold/reloc-types.h
+++ b/gold/reloc-types.h
@@ -79,6 +79,27 @@
   { 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 7f1742d..53c9d19 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -584,13 +584,15 @@
   // 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),
-      got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
-      tls_base_symbol_defined_(false)
+      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)
   { }
 
   // Hook for a new output section.
@@ -1172,6 +1174,10 @@
   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,
@@ -1235,6 +1241,8 @@
   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.
@@ -1431,6 +1439,23 @@
   return this->rela_irelative_;
 }
 
+// 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.
@@ -2966,14 +2991,25 @@
       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;
 
@@ -2991,12 +3027,22 @@
 	  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;
 	    }
 
@@ -3099,15 +3145,7 @@
 	      {
 		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);
 
@@ -3116,6 +3154,24 @@
 			object, r_sym, r_type, got,
 			object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0);
 		  }
+		else if (size == 64
+			 && !is_ifunc
+			 && parameters->options().experimental_use_relr())
+		  {
+		    Relr_section* relr_dyn = target->relr_dyn_section(layout);
+		    unsigned int got_offset =
+		      object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+		    relr_dyn->add_local_relative(object, r_sym, got,
+						 got_offset);
+		  }
+		else
+		  {
+		    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);
+		  }
 	      }
 	  }
 	// For GOTPLT64, we'd normally want a PLT section, but since
@@ -3478,12 +3534,24 @@
 		      || (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
 	      {
@@ -3886,7 +3954,8 @@
 				  ? 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();