2008-05-05 Ian Lance Taylor <iant@google.com>
authorIan Lance Taylor <ian@airs.com>
Tue, 6 May 2008 05:03:15 +0000 (05:03 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 6 May 2008 05:03:15 +0000 (05:03 +0000)
* options.h (DEFINE_bool): For DASH_Z, create the negative option
as noVARNAME rather than no-VARNAME.
(class General_options): Add option -z combreloc.
* output.h (class Output_reloc) [SHT_REL]: Declare compare and
get_address.
(Output_reloc::sort_before) [SHT_REL]: New function.
(Output_reloc::sort_before) [SHT_RELA]: New function.
(class Output_data_reloc_base): Add sort_relocs_ field.  Define
Sort_relocs_comparison.
(Output_data_reloc_base::Output_data_reloc_base): Add sort_relocs
parameter.  Change all callers.
(Output_data_reloc::Output_data_reloc) [both versions]: Add
sort_relocs parameter.  Change all callers.
* output.cc (Output_reloc::get_address): New function, broken out
of write_rel.
(Output_reloc::write_rel): Call it.
(Output_reloc::compare): New function.
(Output_data_reloc_base::do_write): Optionally sort relocs.

gold/ChangeLog
gold/i386.cc
gold/options.h
gold/output.cc
gold/output.h
gold/sparc.cc
gold/x86_64.cc

index 1d9f9d9196117cad523c2c3ca0dd39b518600c79..3ae464f53b0b932ef86e8d5d9d34f529d3f4eaac 100644 (file)
@@ -1,5 +1,24 @@
 2008-05-05  Ian Lance Taylor  <iant@google.com>
 
+       * options.h (DEFINE_bool): For DASH_Z, create the negative option
+       as noVARNAME rather than no-VARNAME.
+       (class General_options): Add option -z combreloc.
+       * output.h (class Output_reloc) [SHT_REL]: Declare compare and
+       get_address.
+       (Output_reloc::sort_before) [SHT_REL]: New function.
+       (Output_reloc::sort_before) [SHT_RELA]: New function.
+       (class Output_data_reloc_base): Add sort_relocs_ field.  Define
+       Sort_relocs_comparison.
+       (Output_data_reloc_base::Output_data_reloc_base): Add sort_relocs
+       parameter.  Change all callers.
+       (Output_data_reloc::Output_data_reloc) [both versions]: Add
+       sort_relocs parameter.  Change all callers.
+       * output.cc (Output_reloc::get_address): New function, broken out
+       of write_rel.
+       (Output_reloc::write_rel): Call it.
+       (Output_reloc::compare): New function.
+       (Output_data_reloc_base::do_write): Optionally sort relocs.
+
        * configure.ac: If targ_extra_obj is set, link it in.
        * configure.tgt: Initialize all variables.
        (x86_64*): Set targ_extra_obj and targ_extra_size.
index 6fb096ea9cdb75345f56492199954773f5910502..9f86229eb0a5477e72c440ea76c942f64ea6700f 100644 (file)
@@ -462,7 +462,7 @@ Target_i386::rel_dyn_section(Layout* layout)
   if (this->rel_dyn_ == NULL)
     {
       gold_assert(layout != NULL);
-      this->rel_dyn_ = new Reloc_section();
+      this->rel_dyn_ = new Reloc_section(parameters->options().combreloc());
       layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
                                      elfcpp::SHF_ALLOC, this->rel_dyn_);
     }
@@ -532,7 +532,7 @@ Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
                                           Output_data_space* got_plt)
   : Output_section_data(4), got_plt_(got_plt), count_(0)
 {
-  this->rel_ = new Reloc_section();
+  this->rel_ = new Reloc_section(false);
   layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
                                  elfcpp::SHF_ALLOC, this->rel_);
 }
index 419e70bb4e1100cc743867c62373f0bf7e8af56b..0dd822104d4cac955054959a6176de241280c138 100644 (file)
@@ -268,7 +268,8 @@ struct Struct_special : public Struct_var
 // These macros allow for easy addition of a new commandline option.
 
 // If no_helpstring__ is not NULL, then in addition to creating
-// VARNAME, we also create an option called no-VARNAME.
+// VARNAME, we also create an option called no-VARNAME (or, for a -z
+// option, noVARNAME).
 #define DEFINE_bool(varname__, dashes__, shortname__, default_value__,   \
                     helpstring__, no_helpstring__)                       \
   DEFINE_var(varname__, dashes__, shortname__, default_value__,          \
@@ -276,7 +277,10 @@ struct Struct_special : public Struct_var
              false, bool, bool, options::parse_bool)                    \
   struct Struct_no_##varname__ : public options::Struct_var              \
   {                                                                      \
-    Struct_no_##varname__() : option("no-" #varname__, dashes__, '\0',   \
+    Struct_no_##varname__() : option((dashes__ == options::DASH_Z       \
+                                     ? "no" #varname__                  \
+                                     : "no-" #varname__),               \
+                                    dashes__, '\0',                     \
                                      default_value__ ? "false" : "true", \
                                      no_helpstring__, NULL, false, this) \
     { }                                                                  \
@@ -699,8 +703,9 @@ class General_options
 
   // The -z options.
 
-  // Both execstack and noexecstack differ from the default execstack_
-  // value, so we need to use different variables for them.
+  DEFINE_bool(combreloc, options::DASH_Z, '\0', true,
+             N_("Sort dynamic relocs"),
+             N_("Do not sort dynamic relocs"));
   DEFINE_uint64(common_page_size, options::DASH_Z, '\0', 0,
                 N_("Set common page size to SIZE"), N_("SIZE"));
   DEFINE_bool(defs, options::DASH_Z, '\0', false,
index a3c1f85690212cc4830ec8d0bb55387008a5b201..12858964850d74c473c7f5db10b12eff6444f45a 100644 (file)
@@ -851,14 +851,11 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
   return offset;
 }
 
-// Write out the offset and info fields of a Rel or Rela relocation
-// entry.
+// Get the output address of a relocation.
 
 template<bool dynamic, int size, bool big_endian>
-template<typename Write_rel>
-void
-Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
-    Write_rel* wr) const
+section_offset_type
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_address() const
 {
   Address address = this->address_;
   if (this->shndx_ != INVALID_CODE)
@@ -878,7 +875,19 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
     }
   else if (this->u2_.od != NULL)
     address += this->u2_.od->address();
-  wr->put_r_offset(address);
+  return address;
+}
+
+// Write out the offset and info fields of a Rel or Rela relocation
+// entry.
+
+template<bool dynamic, int size, bool big_endian>
+template<typename Write_rel>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
+    Write_rel* wr) const
+{
+  wr->put_r_offset(this->get_address());
   unsigned int sym_index = this->is_relative_ ? 0 : this->get_symbol_index();
   wr->put_r_info(elfcpp::elf_r_info<size>(sym_index, this->type_));
 }
@@ -915,6 +924,57 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value(
   return symval->value(this->u1_.relobj, addend);
 }
 
+// Reloc comparison.  This function sorts the dynamic relocs for the
+// benefit of the dynamic linker.  First we sort all relative relocs
+// to the front.  Among relative relocs, we sort by output address.
+// Among non-relative relocs, we sort by symbol index, then by output
+// address.
+
+template<bool dynamic, int size, bool big_endian>
+int
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
+  compare(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>& r2)
+    const
+{
+  if (this->is_relative_)
+    {
+      if (!r2.is_relative_)
+       return -1;
+      // Otherwise sort by reloc address below.
+    }
+  else if (r2.is_relative_)
+    return 1;
+  else
+    {
+      unsigned int sym1 = this->get_symbol_index();
+      unsigned int sym2 = r2.get_symbol_index();
+      if (sym1 < sym2)
+       return -1;
+      else if (sym1 > sym2)
+       return 1;
+      // Otherwise sort by reloc address.
+    }
+
+  section_offset_type addr1 = this->get_address();
+  section_offset_type addr2 = r2.get_address();
+  if (addr1 < addr2)
+    return -1;
+  else if (addr1 > addr2)
+    return 1;
+
+  // Final tie breaker, in order to generate the same output on any
+  // host: reloc type.
+  unsigned int type1 = this->type_;
+  unsigned int type2 = r2.type_;
+  if (type1 < type2)
+    return -1;
+  else if (type1 > type2)
+    return 1;
+
+  // These relocs appear to be exactly the same.
+  return 0;
+}
+
 // Write out a Rela relocation.
 
 template<bool dynamic, int size, bool big_endian>
@@ -964,6 +1024,13 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
   const off_t oview_size = this->data_size();
   unsigned char* const oview = of->get_output_view(off, oview_size);
 
+  if (this->sort_relocs_)
+    {
+      gold_assert(dynamic);
+      std::sort(this->relocs_.begin(), this->relocs_.end(),
+               Sort_relocs_comparison());
+    }
+
   unsigned char* pov = oview;
   for (typename Relocs::const_iterator p = this->relocs_.begin();
        p != this->relocs_.end();
index 9d6577e376e548dfbf3b98a5761a4eda33d8aecb..89c6eeb4487affa4a085fa97b9ad72fc083028a3 100644 (file)
@@ -855,6 +855,19 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   template<typename Write_rel>
   void write_rel(Write_rel*) const;
 
+  // This is used when sorting dynamic relocs.  Return -1 to sort this
+  // reloc before R2, 0 to sort the same as R2, 1 to sort after R2.
+  int
+  compare(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>& r2)
+    const;
+
+  // Return whether this reloc should be sorted before the argument
+  // when sorting dynamic relocs.
+  bool
+  sort_before(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>&
+             r2) const
+  { return this->compare(r2) < 0; }
+
  private:
   // Record that we need a dynamic symbol index.
   void
@@ -864,6 +877,10 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   unsigned int
   get_symbol_index() const;
 
+  // Return the output address.
+  section_offset_type
+  get_address() const;
+
   // Codes for local_sym_index_.
   enum
   {
@@ -986,6 +1003,21 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   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_RELA, dynamic, size, big_endian>&
+             r2) const
+  {
+    int i = this->rel_.compare(r2.rel_);
+    if (i < 0)
+      return false;
+    else if (i > 0)
+      return true;
+    else
+      return this->addend_ < r2.addend_;
+  }
+
  private:
   // The basic reloc.
   Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
@@ -1010,8 +1042,9 @@ class Output_data_reloc_base : public Output_section_data_build
     Reloc_types<sh_type, size, big_endian>::reloc_size;
 
   // Construct the section.
-  Output_data_reloc_base()
-    : Output_section_data_build(Output_data::default_alignment_for_size(size))
+  Output_data_reloc_base(bool sort_relocs)
+    : Output_section_data_build(Output_data::default_alignment_for_size(size)),
+      sort_relocs_(sort_relocs)
   { }
 
  protected:
@@ -1035,7 +1068,19 @@ class Output_data_reloc_base : public Output_section_data_build
  private:
   typedef std::vector<Output_reloc_type> Relocs;
 
+  // The class used to sort the relocations.
+  struct Sort_relocs_comparison
+  {
+    bool
+    operator()(const Output_reloc_type& r1, const Output_reloc_type& r2) const
+    { return r1.sort_before(r2); }
+  };
+
+  // The relocations in this section.
   Relocs relocs_;
+  // Whether to sort the relocations when writing them out, to make
+  // the dynamic linker more efficient.
+  bool sort_relocs_;
 };
 
 // The class which callers actually create.
@@ -1057,8 +1102,8 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   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_REL, dynamic, size, big_endian>()
+  Output_data_reloc(bool sr)
+    : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>(sr)
   { }
 
   // Add a reloc against a global symbol.
@@ -1199,8 +1244,8 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   typedef typename Output_reloc_type::Address Address;
   typedef typename Output_reloc_type::Addend Addend;
 
-  Output_data_reloc()
-    : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>()
+  Output_data_reloc(bool sr)
+    : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>(sr)
   { }
 
   // Add a reloc against a global symbol.
index 60e85241d71cc83c997c35bc676b40f2d188a64a..0472fa14c9f121de80c6a10b340b614cd6964539 100644 (file)
@@ -1026,7 +1026,7 @@ Target_sparc<size, big_endian>::rela_dyn_section(Layout* layout)
   if (this->rela_dyn_ == NULL)
     {
       gold_assert(layout != NULL);
-      this->rela_dyn_ = new Reloc_section();
+      this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
       layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
                                      elfcpp::SHF_ALLOC, this->rela_dyn_);
     }
@@ -1123,7 +1123,7 @@ template<int size, bool big_endian>
 Output_data_plt_sparc<size, big_endian>::Output_data_plt_sparc(Layout* layout)
   : Output_section_data(size == 32 ? 4 : 8), count_(0)
 {
-  this->rel_ = new Reloc_section();
+  this->rel_ = new Reloc_section(false);
   layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
                                  elfcpp::SHF_ALLOC, this->rel_);
 }
index 927ed39be0f6eb7d16304f3b3cc0449e5a4d1e8f..6459e500827b8962f65fb981cd3f1b94db7b8c95 100644 (file)
@@ -465,7 +465,7 @@ Target_x86_64::rela_dyn_section(Layout* layout)
   if (this->rela_dyn_ == NULL)
     {
       gold_assert(layout != NULL);
-      this->rela_dyn_ = new Reloc_section();
+      this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
       layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
                                      elfcpp::SHF_ALLOC, this->rela_dyn_);
     }
@@ -560,7 +560,7 @@ Output_data_plt_x86_64::Output_data_plt_x86_64(Layout* layout,
   : Output_section_data(8), got_(got), got_plt_(got_plt), count_(0),
     tlsdesc_got_offset_(-1U)
 {
-  this->rel_ = new Reloc_section();
+  this->rel_ = new Reloc_section(false);
   layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
                                  elfcpp::SHF_ALLOC, this->rel_);
 }