diff options
Diffstat (limited to 'gold/aarch64.cc')
-rw-r--r-- | gold/aarch64.cc | 132 |
1 files changed, 96 insertions, 36 deletions
diff --git a/gold/aarch64.cc b/gold/aarch64.cc index 33485de61f6..6d55f325d20 100644 --- a/gold/aarch64.cc +++ b/gold/aarch64.cc @@ -2899,6 +2899,8 @@ class Target_aarch64 : public Sized_target<size, big_endian> typedef Target_aarch64<size, big_endian> This; typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Reloc_section; + typedef Output_data_reloc<elfcpp::SHT_RELR, true, size, big_endian> + Relr_section; typedef Relocate_info<size, big_endian> The_relocate_info; typedef typename elfcpp::Elf_types<size>::Elf_Addr Address; typedef AArch64_relobj<size, big_endian> The_aarch64_relobj; @@ -2920,8 +2922,8 @@ class Target_aarch64 : public Sized_target<size, big_endian> : Sized_target<size, big_endian>(info), got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL), got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL), - rela_irelative_(NULL), copy_relocs_(elfcpp::R_AARCH64_COPY), - got_mod_index_offset_(-1U), + rela_irelative_(NULL), relr_dyn_(NULL), + copy_relocs_(elfcpp::R_AARCH64_COPY), got_mod_index_offset_(-1U), tlsdesc_reloc_info_(), tls_base_symbol_defined_(false), stub_tables_(), stub_group_size_(0), aarch64_input_section_map_() { } @@ -3457,6 +3459,10 @@ class Target_aarch64 : public Sized_target<size, big_endian> Reloc_section* rela_irelative_section(Layout*); + // Get the RELR relative relocation section, creating it if necessary. + Relr_section* + relr_dyn_section(Layout*); + // Add a potential copy relocation. void copy_reloc(Symbol_table* symtab, Layout* layout, @@ -3521,6 +3527,8 @@ class Target_aarch64 : public Sized_target<size, big_endian> Reloc_section* rela_dyn_; // The section to use for IRELATIVE relocs. Reloc_section* rela_irelative_; + // The RELR relative relocation section. + Relr_section* relr_dyn_; // Relocs saved to avoid a COPY reloc. Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_; // Offset of the GOT entry for the TLS module index. @@ -3792,6 +3800,23 @@ Target_aarch64<size, big_endian>::rela_irelative_section(Layout* layout) return this->rela_irelative_; } +// Get the RELR relative relocation section, creating it if necessary. + +template<int size, bool big_endian> +typename Target_aarch64<size, big_endian>::Relr_section* +Target_aarch64<size, 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_; +} + // do_make_elf_object to override the same function in the base class. We need // to use a target-specific sub-class of Sized_relobj_file<size, big_endian> to @@ -5643,6 +5668,17 @@ Target_aarch64<size, big_endian>::do_relax( const Task* task) { gold_assert(!parameters->options().relocatable()); + + // 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 (pass == 1) { // We don't handle negative stub_group_size right now. @@ -5711,7 +5747,7 @@ Target_aarch64<size, big_endian>::do_relax( ++sp) (*sp)->finalize_stubs(); - return continue_relaxation; + return relr_changed || continue_relaxation; } @@ -6129,14 +6165,21 @@ Target_aarch64<size, big_endian>::Scan::local( // reloction, so that the dynamic loader can relocate it. if (parameters->options().output_is_position_independent()) { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_local_relative(object, r_sym, - elfcpp::R_AARCH64_RELATIVE, - output_section, - data_shndx, - rela.get_r_offset(), - rela.get_r_addend(), - is_ifunc); + if (parameters->options().relr_relocs() + && rela.get_r_offset() % 2 == 0) + target->relr_dyn_section(layout)->add_local_relative( + object, r_sym, output_section, data_shndx, + rela.get_r_offset()); + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_local_relative(object, r_sym, + elfcpp::R_AARCH64_RELATIVE, + output_section, data_shndx, + rela.get_r_offset(), + rela.get_r_addend(), + is_ifunc); + } } break; @@ -6159,15 +6202,20 @@ Target_aarch64<size, big_endian>::Scan::local( else is_new = got->add_local(object, r_sym, GOT_TYPE_STANDARD); if (is_new && parameters->options().output_is_position_independent()) - target->rela_dyn_section(layout)-> - add_local_relative(object, - r_sym, - elfcpp::R_AARCH64_RELATIVE, - got, - object->local_got_offset(r_sym, - GOT_TYPE_STANDARD), - 0, - false); + { + unsigned int got_offset = + 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* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_local_relative(object, r_sym, + elfcpp::R_AARCH64_RELATIVE, + got, got_offset, 0, false); + } + } } break; @@ -6448,15 +6496,22 @@ Target_aarch64<size, big_endian>::Scan::global( else if (r_type == elfcpp::R_AARCH64_ABS64 && gsym->can_use_relative_reloc(false)) { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global_relative(gsym, - elfcpp::R_AARCH64_RELATIVE, - output_section, - object, - data_shndx, - rela.get_r_offset(), - rela.get_r_addend(), - false); + if (parameters->options().relr_relocs() + && rela.get_r_offset() % 2 == 0) + target->relr_dyn_section(layout)->add_global_relative( + gsym, output_section, object, data_shndx, + rela.get_r_offset()); + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_global_relative(gsym, + elfcpp::R_AARCH64_RELATIVE, + output_section, object, + data_shndx, + rela.get_r_offset(), + rela.get_r_addend(), + false); + } } else { @@ -6595,12 +6650,16 @@ Target_aarch64<size, big_endian>::Scan::global( } if (is_new) { - rela_dyn->add_global_relative( - gsym, elfcpp::R_AARCH64_RELATIVE, - got, - gsym->got_offset(GOT_TYPE_STANDARD), - 0, - false); + 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 + { + rela_dyn->add_global_relative(gsym, + elfcpp::R_AARCH64_RELATIVE, + got, got_off, 0, false); + } } } } @@ -6950,7 +7009,8 @@ Target_aarch64<size, big_endian>::do_finalize_sections( ? NULL : this->plt_->rela_plt()); layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt, - this->rela_dyn_, true, false); + this->rela_dyn_, true, false, + this->relr_dyn_); // Emit any relocs we saved in an attempt to avoid generating COPY // relocs. |