diff options
Diffstat (limited to 'gold/arm.cc')
-rw-r--r-- | gold/arm.cc | 114 |
1 files changed, 93 insertions, 21 deletions
diff --git a/gold/arm.cc b/gold/arm.cc index a5a01bc..5a96faa 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -2116,6 +2116,8 @@ class Target_arm : public Sized_target<32, big_endian> public: typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian> Reloc_section; + typedef Output_data_reloc<elfcpp::SHT_RELR, true, 32, big_endian> + Relr_section; // When were are relocating a stub, we pass this as the relocation number. static const size_t fake_relnum_for_stubs = static_cast<size_t>(-1); @@ -2123,7 +2125,8 @@ class Target_arm : public Sized_target<32, big_endian> Target_arm(const Target::Target_info* info = &arm_info) : Sized_target<32, big_endian>(info), got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL), - rel_dyn_(NULL), rel_irelative_(NULL), copy_relocs_(elfcpp::R_ARM_COPY), + rel_dyn_(NULL), rel_irelative_(NULL), relr_dyn_(NULL), + copy_relocs_(elfcpp::R_ARM_COPY), got_mod_index_offset_(-1U), tls_base_symbol_defined_(false), stub_tables_(), stub_factory_(Stub_factory::get_instance()), should_force_pic_veneer_(false), @@ -2845,6 +2848,10 @@ class Target_arm : public Sized_target<32, big_endian> Reloc_section* rel_tls_desc_section(Layout*) const; + // Get the RELR relative relocation section, creating it if necessary. + Relr_section* + relr_dyn_section(Layout*); + // Return true if the symbol may need a COPY relocation. // References from an executable object to non-function symbols // defined in a dynamic object may need a COPY relocation. @@ -3009,6 +3016,8 @@ class Target_arm : public Sized_target<32, big_endian> Reloc_section* rel_dyn_; // The section to use for IRELATIVE relocs. Reloc_section* rel_irelative_; + // The RELR relative relocation section. + Relr_section* relr_dyn_; // Relocs saved to avoid a COPY reloc. Copy_relocs<elfcpp::SHT_REL, 32, big_endian> copy_relocs_; // Offset of the GOT entry for the TLS module index. @@ -4413,6 +4422,23 @@ Target_arm<big_endian>::rel_irelative_section(Layout* layout) return this->rel_irelative_; } +// Get the RELR relative relocation section, creating it if necessary. + +template<bool big_endian> +typename Target_arm<big_endian>::Relr_section* +Target_arm<big_endian>::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_; +} + // Insn_template methods. @@ -8600,13 +8626,23 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, // relocate it easily. if (parameters->options().output_is_position_independent()) { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - // If we are to add more other reloc types than R_ARM_ABS32, - // we need to add check_non_pic(object, r_type) here. - rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE, - output_section, data_shndx, - reloc.get_r_offset(), is_ifunc); + if (parameters->options().relr_relocs() + && reloc.get_r_offset() % 2 == 0) + { + target->relr_dyn_section(layout)->add_local_relative( + object, r_sym, output_section, data_shndx, + reloc.get_r_offset()); + } + else + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + // If we are to add more other reloc types than R_ARM_ABS32, + // we need to add check_non_pic(object, r_type) here. + rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE, + output_section, data_shndx, + reloc.get_r_offset(), is_ifunc); + } } break; @@ -8729,11 +8765,19 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, // dynamic RELATIVE relocation for this symbol's GOT entry. if (parameters->options().output_is_position_independent()) { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); + unsigned int got_offset = + object->local_got_offset(r_sym, GOT_TYPE_STANDARD); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - rel_dyn->add_local_relative( - object, r_sym, elfcpp::R_ARM_RELATIVE, got, - object->local_got_offset(r_sym, GOT_TYPE_STANDARD)); + if (parameters->options().relr_relocs()) + target->relr_dyn_section(layout)->add_local_relative( + object, r_sym, got, got_offset); + else + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_local_relative(object, r_sym, + elfcpp::R_ARM_RELATIVE, + got, got_offset); + } } } } @@ -9042,10 +9086,18 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, || r_type == elfcpp::R_ARM_ABS32_NOI) && gsym->can_use_relative_reloc(false)) { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE, - output_section, object, - data_shndx, reloc.get_r_offset()); + if (parameters->options().relr_relocs() + && reloc.get_r_offset() % 2 == 0) + target->relr_dyn_section(layout)->add_global_relative( + gsym, output_section, object, data_shndx, reloc.get_r_offset()); + else + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE, + output_section, object, + data_shndx, + reloc.get_r_offset()); + } } else { @@ -9212,9 +9264,18 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, gsym->set_needs_dynsym_value(); } if (is_new) - rel_dyn->add_global_relative( - gsym, elfcpp::R_ARM_RELATIVE, got, - gsym->got_offset(GOT_TYPE_STANDARD)); + { + unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD); + if (parameters->options().relr_relocs()) + target->relr_dyn_section(layout)->add_global_relative( + gsym, got, got_off); + else + { + rel_dyn->add_global_relative(gsym, + elfcpp::R_ARM_RELATIVE, + got, got_off); + } + } } } } @@ -9484,7 +9545,8 @@ Target_arm<big_endian>::do_finalize_sections( ? NULL : this->plt_->rel_plt()); layout->add_target_dynamic_tags(true, this->got_plt_, rel_plt, - this->rel_dyn_, true, false); + this->rel_dyn_, true, false, + this->relr_dyn_); // Emit any relocs we saved in an attempt to avoid generating COPY // relocs. @@ -12360,7 +12422,17 @@ Target_arm<big_endian>::do_relax( // No need to generate stubs if this is a relocatable link. gold_assert(!parameters->options().relocatable()); - // If this is the first pass, we need to group input sections into + // Compute the content of SHT_RELR if present. + bool relr_changed = false; + Layout::Section_list::const_iterator prelr = layout->section_list().begin(); + for (; prelr != layout->section_list().end(); ++prelr) + if ((*prelr)->type() == elfcpp::SHT_RELR) + break; + if (prelr != layout->section_list().end()) + relr_changed = static_cast<Relr_section *>( + (*prelr)->input_sections().begin()->output_section_data())->compute(); + + // If this is the second pass, we need to group input sections into // stub groups. bool done_exidx_fixup = false; typedef typename Stub_table_list::iterator Stub_table_iterator; @@ -12550,7 +12622,7 @@ Target_arm<big_endian>::do_relax( } } - return continue_relaxation; + return relr_changed || continue_relaxation; } // Relocate a stub. |