aboutsummaryrefslogtreecommitdiff
path: root/gold/arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/arm.cc')
-rw-r--r--gold/arm.cc122
1 files changed, 91 insertions, 31 deletions
diff --git a/gold/arm.cc b/gold/arm.cc
index 85f9542..79a9663 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -1064,6 +1064,11 @@ class Arm_exidx_cantunwind : public Output_section_data
this->do_fixed_endian_write<false>(of);
}
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** ARM cantunwind")); }
+
private:
// Implement do_write for a given endianness.
template<bool big_endian>
@@ -1636,7 +1641,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
void
do_relocate_sections(const Symbol_table* symtab, const Layout* layout,
- const unsigned char* pshdrs,
+ const unsigned char* pshdrs, Output_file* of,
typename Sized_relobj<32, big_endian>::Views* pivews);
// Read the symbol information.
@@ -6351,11 +6356,12 @@ Arm_relobj<big_endian>::do_relocate_sections(
const Symbol_table* symtab,
const Layout* layout,
const unsigned char* pshdrs,
+ Output_file* of,
typename Sized_relobj<32, big_endian>::Views* pviews)
{
// Call parent to relocate sections.
Sized_relobj<32, big_endian>::do_relocate_sections(symtab, layout, pshdrs,
- pviews);
+ of, pviews);
// We do not generate stubs if doing a relocatable link.
if (parameters->options().relocatable())
@@ -10944,6 +10950,8 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
Symbol_value<32> symval;
const Symbol_value<32> *psymval;
+ bool is_defined_in_discarded_section;
+ unsigned int shndx;
if (r_sym < local_count)
{
sym = NULL;
@@ -10955,45 +10963,53 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
// counterpart in the kept section. The symbol must not
// correspond to a section we are folding.
bool is_ordinary;
- unsigned int shndx = psymval->input_shndx(&is_ordinary);
- if (is_ordinary
- && shndx != elfcpp::SHN_UNDEF
- && !arm_object->is_section_included(shndx)
- && !(relinfo->symtab->is_section_folded(arm_object, shndx)))
+ shndx = psymval->input_shndx(&is_ordinary);
+ is_defined_in_discarded_section =
+ (is_ordinary
+ && shndx != elfcpp::SHN_UNDEF
+ && !arm_object->is_section_included(shndx)
+ && !relinfo->symtab->is_section_folded(arm_object, shndx));
+
+ // We need to compute the would-be final value of this local
+ // symbol.
+ if (!is_defined_in_discarded_section)
{
- if (comdat_behavior == CB_UNDETERMINED)
- {
- std::string name =
- arm_object->section_name(relinfo->data_shndx);
- comdat_behavior = get_comdat_behavior(name.c_str());
- }
- if (comdat_behavior == CB_PRETEND)
- {
- bool found;
- typename elfcpp::Elf_types<32>::Elf_Addr value =
- arm_object->map_to_kept_section(shndx, &found);
- if (found)
- symval.set_output_value(value + psymval->input_value());
- else
- symval.set_output_value(0);
- }
+ typedef Sized_relobj<32, big_endian> ObjType;
+ typename ObjType::Compute_final_local_value_status status =
+ arm_object->compute_final_local_value(r_sym, psymval, &symval,
+ relinfo->symtab);
+ if (status == ObjType::CFLV_OK)
+ {
+ // Currently we cannot handle a branch to a target in
+ // a merged section. If this is the case, issue an error
+ // and also free the merge symbol value.
+ if (!symval.has_output_value())
+ {
+ const std::string& section_name =
+ arm_object->section_name(shndx);
+ arm_object->error(_("cannot handle branch to local %u "
+ "in a merged section %s"),
+ r_sym, section_name.c_str());
+ }
+ psymval = &symval;
+ }
else
- {
- symval.set_output_value(0);
- }
- symval.set_no_output_symtab_entry();
- psymval = &symval;
+ {
+ // We cannot determine the final value.
+ continue;
+ }
}
}
else
{
- const Symbol* gsym = arm_object->global_symbol(r_sym);
+ const Symbol* gsym;
+ gsym = arm_object->global_symbol(r_sym);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = relinfo->symtab->resolve_forwards(gsym);
sym = static_cast<const Sized_symbol<32>*>(gsym);
- if (sym->has_symtab_index())
+ if (sym->has_symtab_index() && sym->symtab_index() != -1U)
symval.set_output_symtab_index(sym->symtab_index());
else
symval.set_no_output_symtab_entry();
@@ -11010,9 +11026,53 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
// Skip this if the symbol has not output section.
if (status == Symbol_table::CFVS_NO_OUTPUT_SECTION)
continue;
-
symval.set_output_value(value);
+
+ if (gsym->type() == elfcpp::STT_TLS)
+ symval.set_is_tls_symbol();
+ else if (gsym->type() == elfcpp::STT_GNU_IFUNC)
+ symval.set_is_ifunc_symbol();
psymval = &symval;
+
+ is_defined_in_discarded_section =
+ (gsym->is_defined_in_discarded_section()
+ && gsym->is_undefined());
+ shndx = 0;
+ }
+
+ Symbol_value<32> symval2;
+ if (is_defined_in_discarded_section)
+ {
+ if (comdat_behavior == CB_UNDETERMINED)
+ {
+ std::string name = arm_object->section_name(relinfo->data_shndx);
+ comdat_behavior = get_comdat_behavior(name.c_str());
+ }
+ if (comdat_behavior == CB_PRETEND)
+ {
+ // FIXME: This case does not work for global symbols.
+ // We have no place to store the original section index.
+ // Fortunately this does not matter for comdat sections,
+ // only for sections explicitly discarded by a linker
+ // script.
+ bool found;
+ typename elfcpp::Elf_types<32>::Elf_Addr value =
+ arm_object->map_to_kept_section(shndx, &found);
+ if (found)
+ symval2.set_output_value(value + psymval->input_value());
+ else
+ symval2.set_output_value(0);
+ }
+ else
+ {
+ if (comdat_behavior == CB_WARNING)
+ gold_warning_at_location(relinfo, i, offset,
+ _("relocation refers to discarded "
+ "section"));
+ symval2.set_output_value(0);
+ }
+ symval2.set_no_output_symtab_entry();
+ psymval = &symval2;
}
// If symbol is a section symbol, we don't know the actual type of