diff options
author | Ian Lance Taylor <ian@airs.com> | 2008-05-06 05:03:15 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 2008-05-06 05:03:15 +0000 |
commit | d98bc257cffa804406c40b84ecfc8801c2ee90e2 (patch) | |
tree | 3287a837c98dcfaf11d5d3b5d026765d82c3b8cb /gold/output.cc | |
parent | 00d1674256539a39ac940429a2a0171d0e67fc41 (diff) | |
download | gdb-d98bc257cffa804406c40b84ecfc8801c2ee90e2.zip gdb-d98bc257cffa804406c40b84ecfc8801c2ee90e2.tar.gz gdb-d98bc257cffa804406c40b84ecfc8801c2ee90e2.tar.bz2 |
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.
Diffstat (limited to 'gold/output.cc')
-rw-r--r-- | gold/output.cc | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/gold/output.cc b/gold/output.cc index a3c1f85..1285896 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -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(); |