summaryrefslogtreecommitdiff
path: root/gold/aarch64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/aarch64.cc')
-rw-r--r--gold/aarch64.cc132
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.