This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PATCH COMMITTED: Implement -z combrelocs in gold
- From: Ian Lance Taylor <iant at google dot com>
- To: binutils at sourceware dot org
- Date: Mon, 05 May 2008 22:04:36 -0700
- Subject: PATCH COMMITTED: Implement -z combrelocs in gold
This patch implements -z combrelocs in gold, and makes it the
default. This is the option which sorts relocs to optimize dynamic
linker performance.
Ian
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.
Index: i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.73
diff -p -u -r1.73 i386.cc
--- i386.cc 28 Apr 2008 23:09:21 -0000 1.73
+++ i386.cc 6 May 2008 04:52:02 -0000
@@ -462,7 +462,7 @@ Target_i386::rel_dyn_section(Layout* lay
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_i3
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: options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.72
diff -p -u -r1.72 options.h
--- options.h 17 Apr 2008 22:45:47 -0000 1.72
+++ options.h 6 May 2008 04:52:02 -0000
@@ -268,7 +268,8 @@ struct Struct_special : public Struct_va
// 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_va
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: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.74
diff -p -u -r1.74 output.cc
--- output.cc 5 May 2008 19:16:43 -0000 1.74
+++ output.cc 6 May 2008 04:52:02 -0000
@@ -851,14 +851,11 @@ Output_reloc<elfcpp::SHT_REL, dynamic, s
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, s
}
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, s
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,
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: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.66
diff -p -u -r1.66 output.h
--- output.h 5 May 2008 19:16:43 -0000 1.66
+++ output.h 6 May 2008 04:52:03 -0000
@@ -855,6 +855,19 @@ class Output_reloc<elfcpp::SHT_REL, dyna
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, dyna
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, dyn
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 Ou
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 Ou
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,
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
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: sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.5
diff -p -u -r1.5 sparc.cc
--- sparc.cc 19 Apr 2008 18:30:58 -0000 1.5
+++ sparc.cc 6 May 2008 04:52:03 -0000
@@ -1026,7 +1026,7 @@ Target_sparc<size, big_endian>::rela_dyn
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: x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.65
diff -p -u -r1.65 x86_64.cc
--- x86_64.cc 19 Apr 2008 18:30:58 -0000 1.65
+++ x86_64.cc 6 May 2008 04:52:03 -0000
@@ -465,7 +465,7 @@ Target_x86_64::rela_dyn_section(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_
: 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_);
}