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