diff options
Diffstat (limited to 'gold/arm.cc')
-rw-r--r-- | gold/arm.cc | 122 |
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 |