summaryrefslogtreecommitdiffstats
path: root/binutils-2.19/gold/arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'binutils-2.19/gold/arm.cc')
-rw-r--r--binutils-2.19/gold/arm.cc376
1 files changed, 304 insertions, 72 deletions
diff --git a/binutils-2.19/gold/arm.cc b/binutils-2.19/gold/arm.cc
index 76f28be..566e326 100644
--- a/binutils-2.19/gold/arm.cc
+++ b/binutils-2.19/gold/arm.cc
@@ -1320,7 +1320,10 @@ class Arm_output_section : public Output_section
Arm_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
: Output_section(name, type, flags)
- { }
+ {
+ if (type == elfcpp::SHT_ARM_EXIDX)
+ this->set_always_keeps_input_sections();
+ }
~Arm_output_section()
{ }
@@ -1347,6 +1350,10 @@ class Arm_output_section : public Output_section
const Text_section_list& sorted_text_section,
Symbol_table* symtab);
+ // Link an EXIDX section into its corresponding text section.
+ void
+ set_exidx_section_link();
+
private:
// For convenience.
typedef Output_section::Input_section Input_section;
@@ -1371,7 +1378,7 @@ class Arm_exidx_input_section
Arm_exidx_input_section(Relobj* relobj, unsigned int shndx,
unsigned int link, uint32_t size, uint32_t addralign)
: relobj_(relobj), shndx_(shndx), link_(link), size_(size),
- addralign_(addralign)
+ addralign_(addralign), has_errors_(false)
{ }
~Arm_exidx_input_section()
@@ -1404,6 +1411,16 @@ class Arm_exidx_input_section
addralign() const
{ return this->addralign_; }
+ // Whether there are any errors in the EXIDX input section.
+ bool
+ has_errors() const
+ { return this->has_errors_; }
+
+ // Set has-errors flag.
+ void
+ set_has_errors()
+ { this->has_errors_ = true; }
+
private:
// Object containing this.
Relobj* relobj_;
@@ -1415,6 +1432,8 @@ class Arm_exidx_input_section
uint32_t size_;
// Address alignment of this. For ARM 32-bit is sufficient.
uint32_t addralign_;
+ // Whether this has any errors.
+ bool has_errors_;
};
// Arm_relobj class.
@@ -1576,6 +1595,22 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
merge_flags_and_attributes() const
{ return this->merge_flags_and_attributes_; }
+ // Export list of EXIDX section indices.
+ void
+ get_exidx_shndx_list(std::vector<unsigned int>* list) const
+ {
+ list->clear();
+ for (Exidx_section_map::const_iterator p = this->exidx_section_map_.begin();
+ p != this->exidx_section_map_.end();
+ ++p)
+ {
+ if (p->second->shndx() == p->first)
+ list->push_back(p->first);
+ }
+ // Sort list to make result independent of implementation of map.
+ std::sort(list->begin(), list->end());
+ }
+
protected:
// Post constructor setup.
void
@@ -1648,7 +1683,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
void
make_exidx_input_section(unsigned int shndx,
const elfcpp::Shdr<32, big_endian>& shdr,
- unsigned int text_shndx);
+ unsigned int text_shndx,
+ const elfcpp::Shdr<32, big_endian>& text_shdr);
// Return the output address of either a plain input section or a
// relaxed input section. SHNDX is the section index.
@@ -2104,6 +2140,23 @@ class Target_arm : public Sized_target<32, big_endian>
fix_cortex_a8_(false), cortex_a8_relocs_info_()
{ }
+ // Virtual function which is set to return true by a target if
+ // it can use relocation types to determine if a function's
+ // pointer is taken.
+ virtual bool
+ can_check_for_function_pointers() const
+ { return true; }
+
+ // Whether a section called SECTION_NAME may have function pointers to
+ // sections not eligible for safe ICF folding.
+ virtual bool
+ section_may_have_icf_unsafe_pointers(const char* section_name) const
+ {
+ return (!is_prefix_of(".ARM.exidx", section_name)
+ && !is_prefix_of(".ARM.extab", section_name)
+ && Target::section_may_have_icf_unsafe_pointers(section_name));
+ }
+
// Whether we can use BLX.
bool
may_use_blx() const
@@ -2460,8 +2513,7 @@ class Target_arm : public Sized_target<32, big_endian>
Output_section* ,
const elfcpp::Rel<32, big_endian>& ,
unsigned int ,
- const elfcpp::Sym<32, big_endian>&)
- { return false; }
+ const elfcpp::Sym<32, big_endian>&);
inline bool
global_reloc_may_be_function_pointer(Symbol_table* , Layout* , Target_arm* ,
@@ -2469,8 +2521,7 @@ class Target_arm : public Sized_target<32, big_endian>
unsigned int ,
Output_section* ,
const elfcpp::Rel<32, big_endian>& ,
- unsigned int , Symbol*)
- { return false; }
+ unsigned int , Symbol*);
private:
static void
@@ -2501,6 +2552,9 @@ class Target_arm : public Sized_target<32, big_endian>
|| sym->is_preemptible()));
}
+ inline bool
+ possible_function_pointer_reloc(unsigned int r_type);
+
// Whether we have issued an error about a non-PIC compilation.
bool issued_non_pic_error_;
};
@@ -2732,7 +2786,8 @@ class Target_arm : public Sized_target<32, big_endian>
// Fix .ARM.exidx section coverage.
void
- fix_exidx_coverage(Layout*, Arm_output_section<big_endian>*, Symbol_table*);
+ fix_exidx_coverage(Layout*, const Input_objects*,
+ Arm_output_section<big_endian>*, Symbol_table*);
// Functors for STL set.
struct output_section_address_less_than
@@ -5624,10 +5679,6 @@ void
Arm_output_section<big_endian>::append_text_sections_to_list(
Text_section_list* list)
{
- // We only care about text sections.
- if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0)
- return;
-
gold_assert((this->flags() & elfcpp::SHF_ALLOC) != 0);
for (Input_section_list::const_iterator p = this->input_sections().begin();
@@ -5699,9 +5750,10 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
const Arm_exidx_input_section* exidx_input_section =
arm_relobj->exidx_input_section_by_link(shndx);
- // If this text section has no EXIDX section, force an EXIDX_CANTUNWIND
- // entry pointing to the end of the last seen EXIDX section.
- if (exidx_input_section == NULL)
+ // If this text section has no EXIDX section or if the EXIDX section
+ // has errors, force an EXIDX_CANTUNWIND entry pointing to the end
+ // of the last seen EXIDX section.
+ if (exidx_input_section == NULL || exidx_input_section->has_errors())
{
exidx_fixup.add_exidx_cantunwind_as_needed();
continue;
@@ -5785,15 +5837,20 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
if (processed_input_sections.find(Section_id(p->relobj(), p->shndx()))
== processed_input_sections.end())
{
- // We only discard a known EXIDX section because its linked
- // text section has been folded by ICF.
+ // We discard a known EXIDX section because its linked
+ // text section has been folded by ICF. We also discard an
+ // EXIDX section with error, the output does not matter in this
+ // case. We do this to avoid triggering asserts.
Arm_relobj<big_endian>* arm_relobj =
Arm_relobj<big_endian>::as_arm_relobj(p->relobj());
const Arm_exidx_input_section* exidx_input_section =
arm_relobj->exidx_input_section_by_shndx(p->shndx());
gold_assert(exidx_input_section != NULL);
- unsigned int text_shndx = exidx_input_section->link();
- gold_assert(symtab->is_section_folded(p->relobj(), text_shndx));
+ if (!exidx_input_section->has_errors())
+ {
+ unsigned int text_shndx = exidx_input_section->link();
+ gold_assert(symtab->is_section_folded(p->relobj(), text_shndx));
+ }
// Remove this from link. We also need to recount the
// local symbols.
@@ -5812,6 +5869,28 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
this->set_section_offsets_need_adjustment();
}
+// Link EXIDX output sections to text output sections.
+
+template<bool big_endian>
+void
+Arm_output_section<big_endian>::set_exidx_section_link()
+{
+ gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX);
+ if (!this->input_sections().empty())
+ {
+ Input_section_list::const_iterator p = this->input_sections().begin();
+ Arm_relobj<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::as_arm_relobj(p->relobj());
+ unsigned exidx_shndx = p->shndx();
+ const Arm_exidx_input_section* exidx_input_section =
+ arm_relobj->exidx_input_section_by_shndx(exidx_shndx);
+ gold_assert(exidx_input_section != NULL);
+ unsigned int text_shndx = exidx_input_section->link();
+ Output_section* os = arm_relobj->output_section(text_shndx);
+ this->set_link_section(os);
+ }
+}
+
// Arm_relobj methods.
// Determine if an input section is scannable for stub processing. SHDR is
@@ -6413,28 +6492,57 @@ void
Arm_relobj<big_endian>::make_exidx_input_section(
unsigned int shndx,
const elfcpp::Shdr<32, big_endian>& shdr,
- unsigned int text_shndx)
+ unsigned int text_shndx,
+ const elfcpp::Shdr<32, big_endian>& text_shdr)
{
- // Issue an error and ignore this EXIDX section if it points to a text
- // section already has an EXIDX section.
- if (this->exidx_section_map_[text_shndx] != NULL)
- {
- gold_error(_("EXIDX sections %u and %u both link to text section %u "
- "in %s"),
- shndx, this->exidx_section_map_[text_shndx]->shndx(),
- text_shndx, this->name().c_str());
- return;
- }
-
// Create an Arm_exidx_input_section object for this EXIDX section.
Arm_exidx_input_section* exidx_input_section =
new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(),
shdr.get_sh_addralign());
- this->exidx_section_map_[text_shndx] = exidx_input_section;
- // Also map the EXIDX section index to this.
gold_assert(this->exidx_section_map_[shndx] == NULL);
this->exidx_section_map_[shndx] = exidx_input_section;
+
+ if (text_shndx == elfcpp::SHN_UNDEF || text_shndx >= this->shnum())
+ {
+ gold_error(_("EXIDX section %s(%u) links to invalid section %u in %s"),
+ this->section_name(shndx).c_str(), shndx, text_shndx,
+ this->name().c_str());
+ exidx_input_section->set_has_errors();
+ }
+ else if (this->exidx_section_map_[text_shndx] != NULL)
+ {
+ unsigned other_exidx_shndx =
+ this->exidx_section_map_[text_shndx]->shndx();
+ gold_error(_("EXIDX sections %s(%u) and %s(%u) both link to text section"
+ "%s(%u) in %s"),
+ this->section_name(shndx).c_str(), shndx,
+ this->section_name(other_exidx_shndx).c_str(),
+ other_exidx_shndx, this->section_name(text_shndx).c_str(),
+ text_shndx, this->name().c_str());
+ exidx_input_section->set_has_errors();
+ }
+ else
+ this->exidx_section_map_[text_shndx] = exidx_input_section;
+
+ // Check section flags of text section.
+ if ((text_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+ {
+ gold_error(_("EXIDX section %s(%u) links to non-allocated section %s(%u) "
+ " in %s"),
+ this->section_name(shndx).c_str(), shndx,
+ this->section_name(text_shndx).c_str(), text_shndx,
+ this->name().c_str());
+ exidx_input_section->set_has_errors();
+ }
+ else if ((text_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) == 0)
+ // I would like to make this an error but currenlty ld just ignores
+ // this.
+ gold_warning(_("EXIDX section %s(%u) links to non-executable section "
+ "%s(%u) in %s"),
+ this->section_name(shndx).c_str(), shndx,
+ this->section_name(text_shndx).c_str(), text_shndx,
+ this->name().c_str());
}
// Read the symbol information.
@@ -6504,19 +6612,21 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX)
{
unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link());
- if (text_shndx >= this->shnum())
- gold_error(_("EXIDX section %u linked to invalid section %u"),
- i, text_shndx);
- else if (text_shndx == elfcpp::SHN_UNDEF)
+ if (text_shndx == elfcpp::SHN_UNDEF)
deferred_exidx_sections.push_back(i);
else
- this->make_exidx_input_section(i, shdr, text_shndx);
+ {
+ elfcpp::Shdr<32, big_endian> text_shdr(pshdrs
+ + text_shndx * shdr_size);
+ this->make_exidx_input_section(i, shdr, text_shndx, text_shdr);
+ }
}
}
// This is rare.
if (!must_merge_flags_and_attributes)
{
+ gold_assert(deferred_exidx_sections.empty());
this->merge_flags_and_attributes_ = false;
return;
}
@@ -6572,15 +6682,14 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
{
unsigned int shndx = deferred_exidx_sections[i];
elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size);
- unsigned int text_shndx;
+ unsigned int text_shndx = elfcpp::SHN_UNDEF;
Reloc_map::const_iterator it = reloc_map.find(shndx);
- if (it != reloc_map.end()
- && find_linked_text_section(pshdrs + it->second * shdr_size,
- psyms, &text_shndx))
- this->make_exidx_input_section(shndx, shdr, text_shndx);
- else
- gold_error(_("EXIDX section %u has no linked text section."),
- shndx);
+ if (it != reloc_map.end())
+ find_linked_text_section(pshdrs + it->second * shdr_size,
+ psyms, &text_shndx);
+ elfcpp::Shdr<32, big_endian> text_shdr(pshdrs
+ + text_shndx * shdr_size);
+ this->make_exidx_input_section(shndx, shdr, text_shndx, text_shdr);
}
}
}
@@ -7672,6 +7781,72 @@ Target_arm<big_endian>::Scan::unsupported_reloc_global(
object->name().c_str(), r_type, gsym->demangled_name().c_str());
}
+template<bool big_endian>
+inline bool
+Target_arm<big_endian>::Scan::possible_function_pointer_reloc(
+ unsigned int r_type)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_ARM_PC24:
+ case elfcpp::R_ARM_THM_CALL:
+ case elfcpp::R_ARM_PLT32:
+ case elfcpp::R_ARM_CALL:
+ case elfcpp::R_ARM_JUMP24:
+ case elfcpp::R_ARM_THM_JUMP24:
+ case elfcpp::R_ARM_SBREL31:
+ case elfcpp::R_ARM_PREL31:
+ case elfcpp::R_ARM_THM_JUMP19:
+ case elfcpp::R_ARM_THM_JUMP6:
+ case elfcpp::R_ARM_THM_JUMP11:
+ case elfcpp::R_ARM_THM_JUMP8:
+ // All the relocations above are branches except SBREL31 and PREL31.
+ return false;
+
+ default:
+ // Be conservative and assume this is a function pointer.
+ return true;
+ }
+}
+
+template<bool big_endian>
+inline bool
+Target_arm<big_endian>::Scan::local_reloc_may_be_function_pointer(
+ Symbol_table*,
+ Layout*,
+ Target_arm<big_endian>* target,
+ Sized_relobj<32, big_endian>*,
+ unsigned int,
+ Output_section*,
+ const elfcpp::Rel<32, big_endian>&,
+ unsigned int r_type,
+ const elfcpp::Sym<32, big_endian>&)
+{
+ r_type = target->get_real_reloc_type(r_type);
+ return possible_function_pointer_reloc(r_type);
+}
+
+template<bool big_endian>
+inline bool
+Target_arm<big_endian>::Scan::global_reloc_may_be_function_pointer(
+ Symbol_table*,
+ Layout*,
+ Target_arm<big_endian>* target,
+ Sized_relobj<32, big_endian>*,
+ unsigned int,
+ Output_section*,
+ const elfcpp::Rel<32, big_endian>&,
+ unsigned int r_type,
+ Symbol* gsym)
+{
+ // GOT is not a function.
+ if (strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
+ return false;
+
+ r_type = target->get_real_reloc_type(r_type);
+ return possible_function_pointer_reloc(r_type);
+}
+
// Scan a relocation for a global symbol.
template<bool big_endian>
@@ -8090,6 +8265,7 @@ Target_arm<big_endian>::do_finalize_sections(
if (this->attributes_section_data_ == NULL)
this->attributes_section_data_ = new Attributes_section_data(NULL, 0);
+ bool merged_any_attributes = false;
// Merge processor-specific flags.
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
@@ -8104,6 +8280,7 @@ Target_arm<big_endian>::do_finalize_sections(
arm_relobj->processor_specific_flags());
this->merge_object_attributes(arm_relobj->name().c_str(),
arm_relobj->attributes_section_data());
+ merged_any_attributes = true;
}
}
@@ -8118,6 +8295,7 @@ Target_arm<big_endian>::do_finalize_sections(
arm_dynobj->processor_specific_flags());
this->merge_object_attributes(arm_dynobj->name().c_str(),
arm_dynobj->attributes_section_data());
+ merged_any_attributes = true;
}
// Check BLX use.
@@ -8193,9 +8371,9 @@ Target_arm<big_endian>::do_finalize_sections(
}
}
- // Create an .ARM.attributes section unless we have no regular input
- // object. In that case the output will be empty.
- if (input_objects->number_of_relobjs() != 0)
+ // Create an .ARM.attributes section if we have merged any attributes
+ // from inputs.
+ if (merged_any_attributes)
{
Output_attributes_section_data* attributes_section =
new Output_attributes_section_data(*this->attributes_section_data_);
@@ -8204,6 +8382,17 @@ Target_arm<big_endian>::do_finalize_sections(
attributes_section, false, false, false,
false);
}
+
+ // Fix up links in section EXIDX headers.
+ for (Layout::Section_list::const_iterator p = layout->section_list().begin();
+ p != layout->section_list().end();
+ ++p)
+ if ((*p)->type() == elfcpp::SHT_ARM_EXIDX)
+ {
+ Arm_output_section<big_endian>* os =
+ Arm_output_section<big_endian>::as_arm_output_section(*p);
+ os->set_exidx_section_link();
+ }
}
// Return whether a direct absolute static relocation needs to be applied.
@@ -8306,6 +8495,13 @@ Target_arm<big_endian>::Relocate::relocate(
// be converted into an NOP.
is_weakly_undefined_without_plt = true;
}
+ else if (gsym->is_undefined() && reloc_property->uses_symbol())
+ {
+ // This relocation uses the symbol value but the symbol is
+ // undefined. Exit early and have the caller reporting an
+ // error.
+ return true;
+ }
else
{
// Set thumb bit if symbol:
@@ -10760,12 +10956,6 @@ Target_arm<big_endian>::do_relax(
bool stubs_always_after_branch = stub_group_size_param < 0;
section_size_type stub_group_size = abs(stub_group_size_param);
- // The Cortex-A8 erratum fix depends on stubs not being in the same 4K
- // page as the first half of a 32-bit branch straddling two 4K pages.
- // This is a crude way of enforcing that.
- if (this->fix_cortex_a8_)
- stubs_always_after_branch = true;
-
if (stub_group_size == 1)
{
// Default value.
@@ -10775,25 +10965,51 @@ Target_arm<big_endian>::do_relax(
// fixing cortex-a8 errata, the branch range has to be even smaller,
// since wide conditional branch has a range of +-1MB only.
//
- // This value is 24K less than that, which allows for 2025
+ // This value is 48K less than that, which allows for 4096
// 12-byte stubs. If we exceed that, then we will fail to link.
// The user will have to relink with an explicit group size
// option.
- if (this->fix_cortex_a8_)
- stub_group_size = 1024276;
- else
- stub_group_size = 4170000;
+ stub_group_size = 4145152;
+ }
+
+ // The Cortex-A8 erratum fix depends on stubs not being in the same 4K
+ // page as the first half of a 32-bit branch straddling two 4K pages.
+ // This is a crude way of enforcing that. In addition, long conditional
+ // branches of THUMB-2 have a range of +-1M. If we are fixing cortex-A8
+ // erratum, limit the group size to (1M - 12k) to avoid unreachable
+ // cortex-A8 stubs from long conditional branches.
+ if (this->fix_cortex_a8_)
+ {
+ stubs_always_after_branch = true;
+ const section_size_type cortex_a8_group_size = 1024 * (1024 - 12);
+ stub_group_size = std::max(stub_group_size, cortex_a8_group_size);
}
group_sections(layout, stub_group_size, stubs_always_after_branch);
// Also fix .ARM.exidx section coverage.
- Output_section* os = layout->find_output_section(".ARM.exidx");
- if (os != NULL && os->type() == elfcpp::SHT_ARM_EXIDX)
+ Arm_output_section<big_endian>* exidx_output_section = NULL;
+ for (Layout::Section_list::const_iterator p =
+ layout->section_list().begin();
+ p != layout->section_list().end();
+ ++p)
+ if ((*p)->type() == elfcpp::SHT_ARM_EXIDX)
+ {
+ if (exidx_output_section == NULL)
+ exidx_output_section =
+ Arm_output_section<big_endian>::as_arm_output_section(*p);
+ else
+ // We cannot handle this now.
+ gold_error(_("multiple SHT_ARM_EXIDX sections %s and %s in a "
+ "non-relocatable link"),
+ exidx_output_section->name(),
+ (*p)->name());
+ }
+
+ if (exidx_output_section != NULL)
{
- Arm_output_section<big_endian>* exidx_output_section =
- Arm_output_section<big_endian>::as_arm_output_section(os);
- this->fix_exidx_coverage(layout, exidx_output_section, symtab);
+ this->fix_exidx_coverage(layout, input_objects, exidx_output_section,
+ symtab);
done_exidx_fixup = true;
}
}
@@ -11244,6 +11460,7 @@ template<bool big_endian>
void
Target_arm<big_endian>::fix_exidx_coverage(
Layout* layout,
+ const Input_objects* input_objects,
Arm_output_section<big_endian>* exidx_section,
Symbol_table* symtab)
{
@@ -11256,15 +11473,30 @@ Target_arm<big_endian>::fix_exidx_coverage(
typedef std::set<Output_section*, output_section_address_less_than>
Sorted_output_section_list;
Sorted_output_section_list sorted_output_sections;
- Layout::Section_list section_list;
- layout->get_allocated_sections(&section_list);
- for (Layout::Section_list::const_iterator p = section_list.begin();
- p != section_list.end();
+
+ // Find out all the output sections of input sections pointed by
+ // EXIDX input sections.
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
++p)
{
- // We only care about output sections that contain executable code.
- if (((*p)->flags() & elfcpp::SHF_EXECINSTR) != 0)
- sorted_output_sections.insert(*p);
+ Arm_relobj<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::as_arm_relobj(*p);
+ std::vector<unsigned int> shndx_list;
+ arm_relobj->get_exidx_shndx_list(&shndx_list);
+ for (size_t i = 0; i < shndx_list.size(); ++i)
+ {
+ const Arm_exidx_input_section* exidx_input_section =
+ arm_relobj->exidx_input_section_by_shndx(shndx_list[i]);
+ gold_assert(exidx_input_section != NULL);
+ if (!exidx_input_section->has_errors())
+ {
+ unsigned int text_shndx = exidx_input_section->link();
+ Output_section *os = arm_relobj->output_section(text_shndx);
+ if (os != NULL && (os->flags() & elfcpp::SHF_ALLOC) != 0)
+ sorted_output_sections.insert(os);
+ }
+ }
}
// Go over the output sections in ascending order of output addresses.