diff options
author | Ian Lance Taylor <iant@google.com> | 2008-02-27 22:38:18 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2008-02-27 22:38:18 +0000 |
commit | 7019cd256559b48bc642fcb8ff9a4ea9e98bced7 (patch) | |
tree | c88847678e9c212b482d4a30beccdd74abdd90c6 | |
parent | 20b4711e0556d73b7a16250447ee5ca505b834db (diff) | |
download | binutils-gdb-7019cd256559b48bc642fcb8ff9a4ea9e98bced7.tar.gz |
Implement -q/--emit-relocs.
-rw-r--r-- | gold/i386.cc | 4 | ||||
-rw-r--r-- | gold/layout.cc | 8 | ||||
-rw-r--r-- | gold/object.cc | 7 | ||||
-rw-r--r-- | gold/object.h | 38 | ||||
-rw-r--r-- | gold/options.cc | 5 | ||||
-rw-r--r-- | gold/options.h | 10 | ||||
-rw-r--r-- | gold/parameters.cc | 3 | ||||
-rw-r--r-- | gold/parameters.h | 7 | ||||
-rw-r--r-- | gold/reloc.cc | 235 | ||||
-rw-r--r-- | gold/reloc.h | 3 | ||||
-rw-r--r-- | gold/target-reloc.h | 10 | ||||
-rw-r--r-- | gold/x86_64.cc | 4 |
12 files changed, 293 insertions, 41 deletions
diff --git a/gold/i386.cc b/gold/i386.cc index 0655f137276..6b805bdac67 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -2297,7 +2297,7 @@ Target_i386::scan_relocatable_relocs(const General_options& options, typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_REL, Relocatable_size_for_reloc> Scan_relocatable_relocs; - gold::scan_relocatable_relocs<32, false, Target_i386, elfcpp::SHT_REL, + gold::scan_relocatable_relocs<32, false, elfcpp::SHT_REL, Scan_relocatable_relocs>( options, symtab, @@ -2332,7 +2332,7 @@ Target_i386::relocate_for_relocatable( { gold_assert(sh_type == elfcpp::SHT_REL); - gold::relocate_for_relocatable<32, false, Target_i386, elfcpp::SHT_REL>( + gold::relocate_for_relocatable<32, false, elfcpp::SHT_REL>( relinfo, prelocs, reloc_count, diff --git a/gold/layout.cc b/gold/layout.cc index 6685156eac0..e8c6c66ca6c 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -155,8 +155,10 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name, case elfcpp::SHT_RELA: case elfcpp::SHT_REL: case elfcpp::SHT_GROUP: - // For a relocatable link these should be handled elsewhere. - gold_assert(!parameters->output_is_object()); + // If we are emitting relocations these should be handled + // elsewhere. + gold_assert(!parameters->output_is_object() + && !parameters->emit_relocs()); return false; case elfcpp::SHT_PROGBITS: @@ -370,7 +372,7 @@ Layout::layout_reloc(Sized_relobj<size, big_endian>* object, Output_section* data_section, Relocatable_relocs* rr) { - gold_assert(parameters->output_is_object()); + gold_assert(parameters->output_is_object() || parameters->emit_relocs()); int sh_type = shdr.get_sh_type(); diff --git a/gold/object.cc b/gold/object.cc index 3db6f851b9e..c8867170cd2 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -593,8 +593,9 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab, // Keep track of which sections to omit. std::vector<bool> omit(shnum, false); - // Keep track of reloc sections when doing a relocatable link. + // Keep track of reloc sections when emitting relocations. const bool output_is_object = parameters->output_is_object(); + const bool emit_relocs = output_is_object || parameters->emit_relocs(); std::vector<unsigned int> reloc_sections; // Keep track of .eh_frame sections. @@ -660,7 +661,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab, // ones associated with sections which are not being discarded. // However, we don't know that yet for all sections. So save // reloc sections and process them later. - if (output_is_object + if (emit_relocs && (shdr.get_sh_type() == elfcpp::SHT_REL || shdr.get_sh_type() == elfcpp::SHT_RELA)) { @@ -704,7 +705,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab, // When doing a relocatable link handle the reloc sections at the // end. - if (output_is_object) + if (emit_relocs) this->size_relocatable_relocs(); for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin(); p != reloc_sections.end(); diff --git a/gold/object.h b/gold/object.h index 4011bdcf221..80047b0f6a3 100644 --- a/gold/object.h +++ b/gold/object.h @@ -111,6 +111,8 @@ struct Section_relocs Output_section* output_section; // Whether this section has special handling for offsets. bool needs_special_offset_handling; + // Whether the data section is allocated (has the SHF_ALLOC flag set). + bool is_data_section_allocated; }; // Relocations in an object file. This is read in read_relocs and @@ -1312,6 +1314,42 @@ class Sized_relobj : public Relobj relocate_sections(const General_options& options, const Symbol_table*, const Layout*, const unsigned char* pshdrs, Views*); + // Scan the input relocations for --emit-relocs. + void + emit_relocs_scan(const General_options&, Symbol_table*, Layout*, + const unsigned char* plocal_syms, + const Read_relocs_data::Relocs_list::iterator&); + + // Scan the input relocations for --emit-relocs, templatized on the + // type of the relocation section. + template<int sh_type> + void + emit_relocs_scan_reltype(const General_options&, Symbol_table*, Layout*, + const unsigned char* plocal_syms, + const Read_relocs_data::Relocs_list::iterator&, + Relocatable_relocs*); + + // Emit the relocs for --emit-relocs. + void + emit_relocs(const Relocate_info<size, big_endian>*, unsigned int, + unsigned int sh_type, const unsigned char* prelocs, + size_t reloc_count, Output_section*, off_t output_offset, + unsigned char* view, Address address, + section_size_type view_size, + unsigned char* reloc_view, section_size_type reloc_view_size); + + // Emit the relocs for --emit-relocs, templatized on the type of the + // relocation section. + template<int sh_type> + void + emit_relocs_reltype(const Relocate_info<size, big_endian>*, unsigned int, + const unsigned char* prelocs, size_t reloc_count, + Output_section*, off_t output_offset, + unsigned char* view, Address address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size); + // Initialize input to output maps for section symbols in merged // sections. void diff --git a/gold/options.cc b/gold/options.cc index 2dbfad86e51..c65862ed9fd 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -530,8 +530,10 @@ options::Command_line_options::options[] = GENERAL_ARG('\0', "oformat", N_("Set output format (only binary supported)"), N_("--oformat FORMAT"), EXACTLY_TWO_DASHES, &General_options::set_oformat), + GENERAL_NOARG('q', "emit-relocs", N_("Generate relocations in output"), + NULL, TWO_DASHES, &General_options::set_emit_relocs), GENERAL_NOARG('r', "relocatable", N_("Generate relocatable output"), NULL, - ONE_DASH, &General_options::set_relocatable), + TWO_DASHES, &General_options::set_relocatable), // -R really means -rpath, but can mean --just-symbols for // compatibility with GNU ld. -rpath is always -rpath, so we list // it separately. @@ -672,6 +674,7 @@ General_options::General_options() output_file_name_("a.out"), oformat_(OBJECT_FORMAT_ELF), oformat_string_(NULL), + emit_relocs_(false), is_relocatable_(false), strip_(STRIP_NONE), allow_shlib_undefined_(false), diff --git a/gold/options.h b/gold/options.h index 14e1629e52e..c08b391f9f4 100644 --- a/gold/options.h +++ b/gold/options.h @@ -167,6 +167,11 @@ class General_options Target* default_target() const; + // -q: Whether to emit relocations. + bool + emit_relocs() const + { return this->emit_relocs_; } + // -r: Whether we are doing a relocatable link. bool relocatable() const @@ -409,6 +414,10 @@ class General_options set_oformat(const char*); void + set_emit_relocs(bool value) + { this->emit_relocs_ = value; } + + void set_relocatable(bool value) { this->is_relocatable_ = value; } @@ -615,6 +624,7 @@ class General_options const char* output_file_name_; Object_format oformat_; const char* oformat_string_; + bool emit_relocs_; bool is_relocatable_; Strip strip_; bool allow_shlib_undefined_; diff --git a/gold/parameters.cc b/gold/parameters.cc index a53908ffc7c..56de281114d 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -33,7 +33,7 @@ namespace gold Parameters::Parameters(Errors* errors) : errors_(errors), threads_(false), output_file_name_(NULL), - output_file_type_(OUTPUT_INVALID), sysroot_(), + output_file_type_(OUTPUT_INVALID), emit_relocs_(false), sysroot_(), strip_(STRIP_INVALID), allow_shlib_undefined_(false), symbolic_(false), demangle_(false), detect_odr_violations_(false), optimization_level_(0), export_dynamic_(false), debug_(0), @@ -50,6 +50,7 @@ Parameters::set_from_options(const General_options* options) { this->threads_ = options->threads(); this->output_file_name_ = options->output_file_name(); + this->emit_relocs_ = options->emit_relocs(); this->sysroot_ = options->sysroot(); this->allow_shlib_undefined_ = options->allow_shlib_undefined(); this->symbolic_ = options->Bsymbolic(); diff --git a/gold/parameters.h b/gold/parameters.h index 136fd35b845..9d3ebb6ccb9 100644 --- a/gold/parameters.h +++ b/gold/parameters.h @@ -102,6 +102,11 @@ class Parameters output_is_position_independent() const { return output_is_shared(); } + // Whether to emit relocations in the output. + bool + emit_relocs() const + { return this->emit_relocs_; } + // The target system root directory. This is NULL if there isn't // one. const std::string& @@ -298,6 +303,8 @@ class Parameters const char* output_file_name_; // The type of the output file. Output_file_type output_file_type_; + // Whether to emit relocations (-q/--emit-relocs). + bool emit_relocs_; // The target system root directory. std::string sysroot_; // Which symbols to strip. diff --git a/gold/reloc.cc b/gold/reloc.cc index 1920032e1a6..63ebb84d1d5 100644 --- a/gold/reloc.cc +++ b/gold/reloc.cc @@ -29,6 +29,7 @@ #include "output.h" #include "merge.h" #include "object.h" +#include "target-reloc.h" #include "reloc.h" namespace gold @@ -223,13 +224,14 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd) // PLT sections. Relocations for sections which are not // allocated (typically debugging sections) should not add new // GOT and PLT entries. So we skip them unless this is a - // relocatable link. - if (!parameters->output_is_object()) - { - typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size); - if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) - continue; - } + // relocatable link or we need to emit relocations. + typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size); + bool is_section_allocated = ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) + != 0); + if (!is_section_allocated + && !parameters->output_is_object() + && !parameters->emit_relocs()) + continue; if (shdr.get_sh_link() != this->symtab_shndx_) { @@ -272,6 +274,7 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd) sr.reloc_count = reloc_count; sr.output_section = os; sr.needs_special_offset_handling = map_sections[shndx].offset == -1; + sr.is_data_section_allocated = is_section_allocated; } // Read the local symbols. @@ -315,12 +318,20 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options, ++p) { if (!parameters->output_is_object()) - target->scan_relocs(options, symtab, layout, this, p->data_shndx, - p->sh_type, p->contents->data(), p->reloc_count, - p->output_section, - p->needs_special_offset_handling, - this->local_symbol_count_, - local_symbols); + { + // As noted above, when not generating an object file, we + // only scan allocated sections. We may see a non-allocated + // section here if we are emitting relocs. + if (p->is_data_section_allocated) + target->scan_relocs(options, symtab, layout, this, p->data_shndx, + p->sh_type, p->contents->data(), + p->reloc_count, p->output_section, + p->needs_special_offset_handling, + this->local_symbol_count_, + local_symbols); + if (parameters->emit_relocs()) + this->emit_relocs_scan(options, symtab, layout, local_symbols, p); + } else { Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx); @@ -348,6 +359,98 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options, } } +// This is a strategy class we use when scanning for --emit-relocs. + +template<int sh_type> +class Emit_relocs_strategy +{ + public: + // A local non-section symbol. + inline Relocatable_relocs::Reloc_strategy + local_non_section_strategy(unsigned int, Relobj*) + { return Relocatable_relocs::RELOC_COPY; } + + // A local section symbol. + inline Relocatable_relocs::Reloc_strategy + local_section_strategy(unsigned int, Relobj*) + { + if (sh_type == elfcpp::SHT_RELA) + return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA; + else + { + // The addend is stored in the section contents. Since this + // is not a relocatable link, we are going to apply the + // relocation contents to the section as usual. This means + // that we have no way to record the original addend. If the + // original addend is not zero, there is basically no way for + // the user to handle this correctly. Caveat emptor. + return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0; + } + } + + // A global symbol. + inline Relocatable_relocs::Reloc_strategy + global_strategy(unsigned int, Relobj*, unsigned int) + { return Relocatable_relocs::RELOC_COPY; } +}; + +// Scan the input relocations for --emit-relocs. + +template<int size, bool big_endian> +void +Sized_relobj<size, big_endian>::emit_relocs_scan( + const General_options& options, + Symbol_table* symtab, + Layout* layout, + const unsigned char* plocal_syms, + const Read_relocs_data::Relocs_list::iterator& p) +{ + Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx); + gold_assert(rr != NULL); + rr->set_reloc_count(p->reloc_count); + + if (p->sh_type == elfcpp::SHT_REL) + this->emit_relocs_scan_reltype<elfcpp::SHT_REL>(options, symtab, layout, + plocal_syms, p, rr); + else + { + gold_assert(p->sh_type == elfcpp::SHT_RELA); + this->emit_relocs_scan_reltype<elfcpp::SHT_RELA>(options, symtab, + layout, plocal_syms, p, + rr); + } +} + +// Scan the input relocation for --emit-relocs, templatized on the +// type of the relocation section. + +template<int size, bool big_endian> +template<int sh_type> +void +Sized_relobj<size, big_endian>::emit_relocs_scan_reltype( + const General_options& options, + Symbol_table* symtab, + Layout* layout, + const unsigned char* plocal_syms, + const Read_relocs_data::Relocs_list::iterator& p, + Relocatable_relocs* rr) +{ + scan_relocatable_relocs<size, big_endian, sh_type, + Emit_relocs_strategy<sh_type> >( + options, + symtab, + layout, + this, + p->data_shndx, + p->contents->data(), + p->reloc_count, + p->output_section, + p->needs_special_offset_handling, + this->local_symbol_count_, + plocal_syms, + rr); +} + // Relocate the input sections and write out the local symbols. template<int size, bool big_endian> @@ -452,14 +555,15 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs, if (shdr.get_sh_type() == elfcpp::SHT_NOBITS) continue; - if (parameters->output_is_object() + if ((parameters->output_is_object() || parameters->emit_relocs()) && (shdr.get_sh_type() == elfcpp::SHT_REL || shdr.get_sh_type() == elfcpp::SHT_RELA) && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) { - // This is a reloc section in a relocatable link. We don't - // need to read the input file. The size and file offset - // are stored in the Relocatable_relocs structure. + // This is a reloc section in a relocatable link or when + // emitting relocs. We don't need to read the input file. + // The size and file offset are stored in the + // Relocatable_relocs structure. Relocatable_relocs* rr = this->relocatable_relocs(i); gold_assert(rr != NULL); Output_data* posd = rr->output_data(); @@ -670,15 +774,25 @@ Sized_relobj<size, big_endian>::relocate_sections( relinfo.reloc_shndx = i; relinfo.data_shndx = index; if (!parameters->output_is_object()) - target->relocate_section(&relinfo, - sh_type, - prelocs, - reloc_count, - os, - output_offset == -1, - (*pviews)[index].view, - (*pviews)[index].address, - (*pviews)[index].view_size); + { + target->relocate_section(&relinfo, + sh_type, + prelocs, + reloc_count, + os, + output_offset == -1, + (*pviews)[index].view, + (*pviews)[index].address, + (*pviews)[index].view_size); + if (parameters->emit_relocs()) + this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count, + os, output_offset, + (*pviews)[index].view, + (*pviews)[index].address, + (*pviews)[index].view_size, + (*pviews)[i].view, + (*pviews)[i].view_size); + } else { Relocatable_relocs* rr = this->relocatable_relocs(i); @@ -698,6 +812,75 @@ Sized_relobj<size, big_endian>::relocate_sections( } } +// Emit the relocs for --emit-relocs. + +template<int size, bool big_endian> +void +Sized_relobj<size, big_endian>::emit_relocs( + const Relocate_info<size, big_endian>* relinfo, + unsigned int i, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + off_t offset_in_output_section, + unsigned char* view, + typename elfcpp::Elf_types<size>::Elf_Addr address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size) +{ + if (sh_type == elfcpp::SHT_REL) + this->emit_relocs_reltype<elfcpp::SHT_REL>(relinfo, i, prelocs, + reloc_count, output_section, + offset_in_output_section, + view, address, view_size, + reloc_view, reloc_view_size); + else + { + gold_assert(sh_type == elfcpp::SHT_RELA); + this->emit_relocs_reltype<elfcpp::SHT_RELA>(relinfo, i, prelocs, + reloc_count, output_section, + offset_in_output_section, + view, address, view_size, + reloc_view, reloc_view_size); + } +} + +// Emit the relocs for --emit-relocs, templatized on the type of the +// relocation section. + +template<int size, bool big_endian> +template<int sh_type> +void +Sized_relobj<size, big_endian>::emit_relocs_reltype( + const Relocate_info<size, big_endian>* relinfo, + unsigned int i, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + off_t offset_in_output_section, + unsigned char* view, + typename elfcpp::Elf_types<size>::Elf_Addr address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size) +{ + const Relocatable_relocs* rr = this->relocatable_relocs(i); + relocate_for_relocatable<size, big_endian, sh_type>( + relinfo, + prelocs, + reloc_count, + output_section, + offset_in_output_section, + rr, + view, + address, + view_size, + reloc_view, + reloc_view_size); +} + // Create merge hash tables for the local symbols. These are used to // speed up relocations. diff --git a/gold/reloc.h b/gold/reloc.h index 438e8613514..fb6c8460b43 100644 --- a/gold/reloc.h +++ b/gold/reloc.h @@ -194,6 +194,9 @@ class Relocatable_relocs // SHT_RELA reloc and the contents of the data section do not need // to be changed. RELOC_ADJUST_FOR_SECTION_RELA, + // Like RELOC_ADJUST_FOR_SECTION_RELA but the addend should not be + // adjusted. + RELOC_ADJUST_FOR_SECTION_0, // Like RELOC_ADJUST_FOR_SECTION_RELA but the contents of the // section need to be changed. The number indicates the number of // bytes in the addend in the section contents. diff --git a/gold/target-reloc.h b/gold/target-reloc.h index 3fd96c3a52c..2bc0a1b3b69 100644 --- a/gold/target-reloc.h +++ b/gold/target-reloc.h @@ -256,7 +256,7 @@ class Default_scan_relocatable_relocs switch (classify.get_size_for_reloc(r_type, object)) { case 0: - return Relocatable_relocs::RELOC_COPY; + return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0; case 1: return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1; case 2: @@ -286,7 +286,7 @@ class Default_scan_relocatable_relocs // local_section_strategy. Most targets should be able to use // Default_scan_relocatable_relocs as this class. -template<int size, bool big_endian, typename Target_type, int sh_type, +template<int size, bool big_endian, int sh_type, typename Scan_relocatable_reloc> void scan_relocatable_relocs( @@ -365,7 +365,7 @@ scan_relocatable_relocs( // Relocate relocs during a relocatable link. This is a default // definition which should work for most targets. -template<int size, bool big_endian, typename Target_type, int sh_type> +template<int size, bool big_endian, int sh_type> void relocate_for_relocatable( const Relocate_info<size, big_endian>* relinfo, @@ -416,6 +416,7 @@ relocate_for_relocatable( break; case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA: + case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0: case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1: case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2: case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4: @@ -503,6 +504,9 @@ relocate_for_relocatable( } break; + case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0: + break; + case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1: Relocate_functions<size, big_endian>::rel8(padd, object, psymval); diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 882398f487a..3ceb798614d 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -2087,7 +2087,7 @@ Target_x86_64::scan_relocatable_relocs(const General_options& options, typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA, Relocatable_size_for_reloc> Scan_relocatable_relocs; - gold::scan_relocatable_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA, + gold::scan_relocatable_relocs<64, false, elfcpp::SHT_RELA, Scan_relocatable_relocs>( options, symtab, @@ -2122,7 +2122,7 @@ Target_x86_64::relocate_for_relocatable( { gold_assert(sh_type == elfcpp::SHT_RELA); - gold::relocate_for_relocatable<64, false, Target_x86_64, elfcpp::SHT_RELA>( + gold::relocate_for_relocatable<64, false, elfcpp::SHT_RELA>( relinfo, prelocs, reloc_count, |