X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Farm.cc;h=ad11c1bb007fd57102a36135c96867c41c67cbf8;hb=5496abe1c5c31aa6648e8fdb15e4122025bcabfe;hp=f1d4fe930bb70a8356a6b12293048d69073e165c;hpb=07f107f306e422497915e62f6c3d3d6d7b20e8e1;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/arm.cc b/gold/arm.cc index f1d4fe930b..ad11c1bb00 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1,6 +1,6 @@ // arm.cc -- arm target support for gold. -// Copyright (C) 2009-2015 Free Software Foundation, Inc. +// Copyright (C) 2009-2020 Free Software Foundation, Inc. // Written by Doug Kwan based on the i386 code // by Ian Lance Taylor . // This file also contains borrowed and adapted code from @@ -62,7 +62,10 @@ template class Output_data_plt_arm; template -class Output_data_plt_arm_standard; +class Output_data_plt_arm_short; + +template +class Output_data_plt_arm_long; template class Stub_table; @@ -126,7 +129,7 @@ const size_t ARM_TCB_SIZE = 8; // Target::do_select_as_default_target() hook so that we do not spend time // building the table if we are not linking ARM objects. // -// An alternative is to to process the information in arm-reloc.def in +// An alternative is to process the information in arm-reloc.def in // compilation time and generate a representation of it in PODs only. That // way we can avoid initialization when the linker starts. @@ -594,7 +597,7 @@ class Reloc_stub : public Stub // Name of key. This is mainly for debugging. std::string - name() const; + name() const ATTRIBUTE_UNUSED; private: // Stub type. @@ -2037,9 +2040,9 @@ class Arm_output_data_got : public Output_data_got<32, big_endian> // bits. The default handling of relocatable relocation cannot process these // relocations. So we have to extend the default code. -template +template class Arm_scan_relocatable_relocs : - public Default_scan_relocatable_relocs + public Default_scan_relocatable_relocs { public: // Return the strategy to use for a local symbol which is a section @@ -2047,7 +2050,7 @@ class Arm_scan_relocatable_relocs : inline Relocatable_relocs::Reloc_strategy local_section_strategy(unsigned int r_type, Relobj*) { - if (sh_type == elfcpp::SHT_RELA) + if (Classify_reloc::sh_type == elfcpp::SHT_RELA) return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA; else { @@ -2125,7 +2128,10 @@ class Target_arm : public Sized_target<32, big_endian> stub_tables_(), stub_factory_(Stub_factory::get_instance()), should_force_pic_veneer_(false), arm_input_section_map_(), attributes_section_data_(NULL), - fix_cortex_a8_(false), cortex_a8_relocs_info_() + fix_cortex_a8_(false), cortex_a8_relocs_info_(), + target1_reloc_(elfcpp::R_ARM_ABS32), + // This can be any reloc type but usually is R_ARM_GOT_PREL. + target2_reloc_(elfcpp::R_ARM_GOT_PREL) { } // Whether we force PCI branch veneers. @@ -2298,6 +2304,21 @@ class Target_arm : public Sized_target<32, big_endian> const unsigned char* plocal_symbols, Relocatable_relocs*); + // Scan the relocs for --emit-relocs. + void + emit_relocs_scan(Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, big_endian>* object, + unsigned int data_shndx, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + size_t local_symbol_count, + const unsigned char* plocal_syms, + Relocatable_relocs* rr); + // Emit relocations for a section. void relocate_relocs(const Relocate_info<32, big_endian>*, @@ -2307,7 +2328,6 @@ class Target_arm : public Sized_target<32, big_endian> Output_section* output_section, typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section, - const Relocatable_relocs*, unsigned char* view, Arm_address view_address, section_size_type view_size, @@ -2374,8 +2394,8 @@ class Target_arm : public Sized_target<32, big_endian> rel_irelative_section(Layout*); // Map platform-specific reloc types - static unsigned int - get_real_reloc_type(unsigned int r_type); + unsigned int + get_real_reloc_type(unsigned int r_type) const; // // Methods to support stub-generations. @@ -2526,6 +2546,30 @@ class Target_arm : public Sized_target<32, big_endian> // as the default. gold_assert(arm_reloc_property_table == NULL); arm_reloc_property_table = new Arm_reloc_property_table(); + if (parameters->options().user_set_target1_rel()) + { + // FIXME: This is not strictly compatible with ld, which allows both + // --target1-abs and --target-rel to be given. + if (parameters->options().user_set_target1_abs()) + gold_error(_("Cannot use both --target1-abs and --target1-rel.")); + else + this->target1_reloc_ = elfcpp::R_ARM_REL32; + } + // We don't need to handle --target1-abs because target1_reloc_ is set + // to elfcpp::R_ARM_ABS32 in the member initializer list. + + if (parameters->options().user_set_target2()) + { + const char* target2 = parameters->options().target2(); + if (strcmp(target2, "rel") == 0) + this->target2_reloc_ = elfcpp::R_ARM_REL32; + else if (strcmp(target2, "abs") == 0) + this->target2_reloc_ = elfcpp::R_ARM_ABS32; + else if (strcmp(target2, "got-rel") == 0) + this->target2_reloc_ = elfcpp::R_ARM_GOT_PREL; + else + gold_unreachable(); + } } // Virtual function which is set to return true by a target if @@ -2555,7 +2599,11 @@ class Target_arm : public Sized_target<32, big_endian> Output_data_space* got_irelative) { gold_assert(got_plt != NULL && got_irelative != NULL); - return new Output_data_plt_arm_standard( + if (parameters->options().long_plt()) + return new Output_data_plt_arm_long( + layout, got, got_plt, got_irelative); + else + return new Output_data_plt_arm_short( layout, got, got_plt, got_irelative); } @@ -2669,13 +2717,10 @@ class Target_arm : public Sized_target<32, big_endian> // Do a relocation. Return false if the caller should not issue // any warnings about this relocation. inline bool - relocate(const Relocate_info<32, big_endian>*, Target_arm*, - Output_section*, size_t relnum, - const elfcpp::Rel<32, big_endian>&, - unsigned int r_type, const Sized_symbol<32>*, - const Symbol_value<32>*, - unsigned char*, Arm_address, - section_size_type); + relocate(const Relocate_info<32, big_endian>*, unsigned int, + Target_arm*, Output_section*, size_t, const unsigned char*, + const Sized_symbol<32>*, const Symbol_value<32>*, + unsigned char*, Arm_address, section_size_type); // Return whether we want to pass flag NON_PIC_REF for this // reloc. This means the relocation type accesses a symbol not via @@ -2724,12 +2769,23 @@ class Target_arm : public Sized_target<32, big_endian> }; - // A class which returns the size required for a relocation type, - // used while scanning relocs during a relocatable link. - class Relocatable_size_for_reloc + // A class for inquiring about properties of a relocation, + // used while scanning relocs during a relocatable link and + // garbage collection. + class Classify_reloc : + public gold::Default_classify_reloc { public: - unsigned int + typedef typename Reloc_types::Reloc + Reltype; + + // Return the explicit addend of the relocation (return 0 for SHT_REL). + static typename elfcpp::Elf_types<32>::Elf_Swxword + get_r_addend(const Reltype*) + { return 0; } + + // Return the size of the addend of the relocation (only used for SHT_REL). + static unsigned int get_size_for_reloc(unsigned int, Relobj*); }; @@ -2806,9 +2862,11 @@ class Target_arm : public Sized_target<32, big_endian> unsigned int shndx, Output_section* output_section, Symbol* sym, const elfcpp::Rel<32, big_endian>& reloc) { + unsigned int r_type = elfcpp::elf_r_type<32>(reloc.get_r_info()); this->copy_relocs_.copy_reloc(symtab, layout, symtab->get_sized_symbol<32>(sym), - object, shndx, output_section, reloc, + object, shndx, output_section, + r_type, reloc.get_r_offset(), 0, this->rel_dyn_section(layout)); } @@ -2971,6 +3029,11 @@ class Target_arm : public Sized_target<32, big_endian> bool fix_cortex_a8_; // Map addresses to relocs for Cortex-A8 erratum. Cortex_a8_relocs_info cortex_a8_relocs_info_; + // What R_ARM_TARGET1 maps to. It can be R_ARM_REL32 or R_ARM_ABS32. + unsigned int target1_reloc_; + // What R_ARM_TARGET2 maps to. It should be one of R_ARM_REL32, R_ARM_ABS32 + // and R_ARM_GOT_PREL. + unsigned int target2_reloc_; }; template @@ -2997,7 +3060,9 @@ const Target::Target_info Target_arm::arm_info = 0, // large_common_section_flags ".ARM.attributes", // attributes_section "aeabi", // attributes_vendor - "_start" // entry_symbol_name + "_start", // entry_symbol_name + 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; // Arm relocate functions class @@ -3360,7 +3425,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> const Symbol_value<32>* psymval, Arm_address address, Arm_address thumb_bit); - // R_ARM_THM_JUMP6: S + A – P + // R_ARM_THM_JUMP6: S + A - P static inline typename This::Status thm_jump6(unsigned char* view, const Sized_relobj_file<32, big_endian>* object, @@ -3371,7 +3436,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> typedef typename elfcpp::Swap<16, big_endian>::Valtype Reltype; Valtype* wv = reinterpret_cast(view); Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); - // bit[9]:bit[7:3]:’0’ (mask: 0x02f8) + // bit[9]:bit[7:3]:'0' (mask: 0x02f8) Reltype addend = (((val & 0x0200) >> 3) | ((val & 0x00f8) >> 2)); Reltype x = (psymval->value(object, addend) - address); val = (val & 0xfd07) | ((x & 0x0040) << 3) | ((val & 0x003e) << 2); @@ -3382,7 +3447,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> : This::STATUS_OKAY); } - // R_ARM_THM_JUMP8: S + A – P + // R_ARM_THM_JUMP8: S + A - P static inline typename This::Status thm_jump8(unsigned char* view, const Sized_relobj_file<32, big_endian>* object, @@ -3402,7 +3467,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> : This::STATUS_OKAY); } - // R_ARM_THM_JUMP11: S + A – P + // R_ARM_THM_JUMP11: S + A - P static inline typename This::Status thm_jump11(unsigned char* view, const Sized_relobj_file<32, big_endian>* object, @@ -4452,30 +4517,49 @@ Stub::do_fixed_endian_write(unsigned char* view, section_size_type view_size) { const Stub_template* stub_template = this->stub_template(); const Insn_template* insns = stub_template->insns(); + const bool enable_be8 = parameters->options().be8(); - // FIXME: We do not handle BE8 encoding yet. unsigned char* pov = view; for (size_t i = 0; i < stub_template->insn_count(); i++) { switch (insns[i].type()) { case Insn_template::THUMB16_TYPE: - elfcpp::Swap<16, big_endian>::writeval(pov, insns[i].data() & 0xffff); + if (enable_be8) + elfcpp::Swap<16, false>::writeval(pov, insns[i].data() & 0xffff); + else + elfcpp::Swap<16, big_endian>::writeval(pov, + insns[i].data() & 0xffff); break; case Insn_template::THUMB16_SPECIAL_TYPE: - elfcpp::Swap<16, big_endian>::writeval( - pov, - this->thumb16_special(i)); + if (enable_be8) + elfcpp::Swap<16, false>::writeval(pov, this->thumb16_special(i)); + else + elfcpp::Swap<16, big_endian>::writeval(pov, + this->thumb16_special(i)); break; case Insn_template::THUMB32_TYPE: { uint32_t hi = (insns[i].data() >> 16) & 0xffff; uint32_t lo = insns[i].data() & 0xffff; - elfcpp::Swap<16, big_endian>::writeval(pov, hi); - elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo); + if (enable_be8) + { + elfcpp::Swap<16, false>::writeval(pov, hi); + elfcpp::Swap<16, false>::writeval(pov + 2, lo); + } + else + { + elfcpp::Swap<16, big_endian>::writeval(pov, hi); + elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo); + } } break; case Insn_template::ARM_TYPE: + if (enable_be8) + elfcpp::Swap<32, false>::writeval(pov, insns[i].data()); + else + elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data()); + break; case Insn_template::DATA_TYPE: elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data()); break; @@ -4542,7 +4626,7 @@ Reloc_stub::stub_type_for_reloc( // This is a bit ugly but we want to avoid using a templated class for // big and little endianities. bool may_use_blx; - bool should_force_pic_veneer; + bool should_force_pic_veneer = parameters->options().pic_veneer(); bool thumb2; bool thumb_only; if (parameters->target().is_big_endian()) @@ -4550,7 +4634,7 @@ Reloc_stub::stub_type_for_reloc( const Target_arm* big_endian_target = Target_arm::default_target(); may_use_blx = big_endian_target->may_use_v5t_interworking(); - should_force_pic_veneer = big_endian_target->should_force_pic_veneer(); + should_force_pic_veneer |= big_endian_target->should_force_pic_veneer(); thumb2 = big_endian_target->using_thumb2(); thumb_only = big_endian_target->using_thumb_only(); } @@ -4559,7 +4643,8 @@ Reloc_stub::stub_type_for_reloc( const Target_arm* little_endian_target = Target_arm::default_target(); may_use_blx = little_endian_target->may_use_v5t_interworking(); - should_force_pic_veneer = little_endian_target->should_force_pic_veneer(); + should_force_pic_veneer |= + little_endian_target->should_force_pic_veneer(); thumb2 = little_endian_target->using_thumb2(); thumb_only = little_endian_target->using_thumb_only(); } @@ -6255,16 +6340,9 @@ Arm_relobj::scan_section_for_cortex_a8_erratum( this->mapping_symbols_info_.lower_bound(section_start); // There are no mapping symbols for this section. Treat it as a data-only - // section. Issue a warning if section is marked as containing - // instructions. + // section. if (p == this->mapping_symbols_info_.end() || p->first.first != shndx) - { - if ((this->section_flags(shndx) & elfcpp::SHF_EXECINSTR) != 0) - gold_warning(_("cannot scan executable section %u of %s for Cortex-A8 " - "erratum because it has no mapping symbols."), - shndx, this->name().c_str()); - return; - } + return; Arm_address output_address = this->simple_input_section_output_address(shndx, os); @@ -6529,9 +6607,9 @@ Arm_relobj::do_relocate_sections( Output_file* of, typename Sized_relobj_file<32, big_endian>::Views* pviews) { - // Call parent to relocate sections. - Sized_relobj_file<32, big_endian>::do_relocate_sections(symtab, layout, - pshdrs, of, pviews); + // Relocate the section data. + this->relocate_section_range(symtab, layout, pshdrs, of, pviews, + 1, this->shnum() - 1); // We do not generate stubs if doing a relocatable link. if (parameters->options().relocatable()) @@ -6613,6 +6691,80 @@ Arm_relobj::do_relocate_sections( section_address, section_size); } + // BE8 swapping + if (parameters->options().be8()) + { + section_size_type span_start, span_end; + elfcpp::Shdr<32, big_endian> + shdr(pshdrs + i * elfcpp::Elf_sizes<32>::shdr_size); + Mapping_symbol_position section_start(i, 0); + typename Mapping_symbols_info::const_iterator p = + this->mapping_symbols_info_.lower_bound(section_start); + unsigned char* view = (*pviews)[i].view; + Arm_address view_address = (*pviews)[i].address; + section_size_type view_size = (*pviews)[i].view_size; + while (p != this->mapping_symbols_info_.end() + && p->first.first == i) + { + typename Mapping_symbols_info::const_iterator next = + this->mapping_symbols_info_.upper_bound(p->first); + + // Only swap arm or thumb code. + if ((p->second == 'a') || (p->second == 't')) + { + Output_section* os = this->output_section(i); + gold_assert(os != NULL); + Arm_address section_address = + this->simple_input_section_output_address(i, os); + span_start = convert_to_section_size_type(p->first.second); + if (next != this->mapping_symbols_info_.end() + && next->first.first == i) + span_end = + convert_to_section_size_type(next->first.second); + else + span_end = + convert_to_section_size_type(shdr.get_sh_size()); + unsigned char* section_view = + view + (section_address - view_address); + uint64_t section_size = this->section_size(i); + + gold_assert(section_address >= view_address + && ((section_address + section_size) + <= (view_address + view_size))); + + // Set Output view for swapping + unsigned char *oview = section_view + span_start; + unsigned int index = 0; + if (p->second == 'a') + { + while (index + 3 < (span_end - span_start)) + { + typedef typename elfcpp::Swap<32, big_endian> + ::Valtype Valtype; + Valtype* wv = + reinterpret_cast(oview+index); + uint32_t val = elfcpp::Swap<32, false>::readval(wv); + elfcpp::Swap<32, true>::writeval(wv, val); + index += 4; + } + } + else if (p->second == 't') + { + while (index + 1 < (span_end - span_start)) + { + typedef typename elfcpp::Swap<16, big_endian> + ::Valtype Valtype; + Valtype* wv = + reinterpret_cast(oview+index); + uint16_t val = elfcpp::Swap<16, false>::readval(wv); + elfcpp::Swap<16, true>::writeval(wv, val); + index += 2; + } + } + } + p = next; + } + } } } @@ -7722,29 +7874,14 @@ class Output_data_plt_arm_standard : public Output_data_plt_arm do_first_plt_entry_offset() const { return sizeof(first_plt_entry); } - // Return the size of a PLT entry. - virtual unsigned int - do_get_plt_entry_size() const - { return sizeof(plt_entry); } - virtual void do_fill_first_plt_entry(unsigned char* pov, Arm_address got_address, Arm_address plt_address); - virtual void - do_fill_plt_entry(unsigned char* pov, - Arm_address got_address, - Arm_address plt_address, - unsigned int got_offset, - unsigned int plt_offset); - private: // Template for the first PLT entry. static const uint32_t first_plt_entry[5]; - - // Template for subsequent PLT entries. - static const uint32_t plt_entry[3]; }; // ARM PLTs. @@ -7772,18 +7909,59 @@ Output_data_plt_arm_standard::do_fill_first_plt_entry( { // Write first PLT entry. All but the last word are constants. const size_t num_first_plt_words = (sizeof(first_plt_entry) - / sizeof(plt_entry[0])); + / sizeof(first_plt_entry[0])); for (size_t i = 0; i < num_first_plt_words - 1; i++) - elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]); + { + if (parameters->options().be8()) + { + elfcpp::Swap<32, false>::writeval(pov + i * 4, + first_plt_entry[i]); + } + else + { + elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, + first_plt_entry[i]); + } + } // Last word in first PLT entry is &GOT[0] - . elfcpp::Swap<32, big_endian>::writeval(pov + 16, got_address - (plt_address + 16)); } // Subsequent entries in the PLT. +// This class generates short (12-byte) entries, for displacements up to 2^28. + +template +class Output_data_plt_arm_short : public Output_data_plt_arm_standard +{ + public: + Output_data_plt_arm_short(Layout* layout, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_data_plt_arm_standard(layout, got, got_plt, got_irelative) + { } + + protected: + // Return the size of a PLT entry. + virtual unsigned int + do_get_plt_entry_size() const + { return sizeof(plt_entry); } + + virtual void + do_fill_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset); + + private: + // Template for subsequent PLT entries. + static const uint32_t plt_entry[3]; +}; template -const uint32_t Output_data_plt_arm_standard::plt_entry[3] = +const uint32_t Output_data_plt_arm_short::plt_entry[3] = { 0xe28fc600, // add ip, pc, #0xNN00000 0xe28cca00, // add ip, ip, #0xNN000 @@ -7792,7 +7970,7 @@ const uint32_t Output_data_plt_arm_standard::plt_entry[3] = template void -Output_data_plt_arm_standard::do_fill_plt_entry( +Output_data_plt_arm_short::do_fill_plt_entry( unsigned char* pov, Arm_address got_address, Arm_address plt_address, @@ -7801,14 +7979,98 @@ Output_data_plt_arm_standard::do_fill_plt_entry( { int32_t offset = ((got_address + got_offset) - (plt_address + plt_offset + 8)); + if (offset < 0 || offset > 0x0fffffff) + gold_error(_("PLT offset too large, try linking with --long-plt")); - gold_assert(offset >= 0 && offset < 0x0fffffff); uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff); - elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff); - elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1); uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff); - elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); + + if (parameters->options().be8()) + { + elfcpp::Swap<32, false>::writeval(pov, plt_insn0); + elfcpp::Swap<32, false>::writeval(pov + 4, plt_insn1); + elfcpp::Swap<32, false>::writeval(pov + 8, plt_insn2); + } + else + { + elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1); + elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); + } +} + +// This class generates long (16-byte) entries, for arbitrary displacements. + +template +class Output_data_plt_arm_long : public Output_data_plt_arm_standard +{ + public: + Output_data_plt_arm_long(Layout* layout, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_data_plt_arm_standard(layout, got, got_plt, got_irelative) + { } + + protected: + // Return the size of a PLT entry. + virtual unsigned int + do_get_plt_entry_size() const + { return sizeof(plt_entry); } + + virtual void + do_fill_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset); + + private: + // Template for subsequent PLT entries. + static const uint32_t plt_entry[4]; +}; + +template +const uint32_t Output_data_plt_arm_long::plt_entry[4] = +{ + 0xe28fc200, // add ip, pc, #0xN0000000 + 0xe28cc600, // add ip, ip, #0xNN00000 + 0xe28cca00, // add ip, ip, #0xNN000 + 0xe5bcf000, // ldr pc, [ip, #0xNNN]! +}; + +template +void +Output_data_plt_arm_long::do_fill_plt_entry( + unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset) +{ + int32_t offset = ((got_address + got_offset) + - (plt_address + plt_offset + 8)); + + uint32_t plt_insn0 = plt_entry[0] | (offset >> 28); + uint32_t plt_insn1 = plt_entry[1] | ((offset >> 20) & 0xff); + uint32_t plt_insn2 = plt_entry[2] | ((offset >> 12) & 0xff); + uint32_t plt_insn3 = plt_entry[3] | (offset & 0xfff); + + if (parameters->options().be8()) + { + elfcpp::Swap<32, false>::writeval(pov, plt_insn0); + elfcpp::Swap<32, false>::writeval(pov + 4, plt_insn1); + elfcpp::Swap<32, false>::writeval(pov + 8, plt_insn2); + elfcpp::Swap<32, false>::writeval(pov + 12, plt_insn3); + } + else + { + elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1); + elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); + elfcpp::Swap<32, big_endian>::writeval(pov + 12, plt_insn3); + } } // Write out the PLT. This uses the hand-coded instructions above, @@ -8310,7 +8572,7 @@ Target_arm::Scan::local(Symbol_table* symtab, if (is_discarded) return; - r_type = get_real_reloc_type(r_type); + r_type = target->get_real_reloc_type(r_type); // A local STT_GNU_IFUNC symbol may require a PLT entry. bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC; @@ -8716,7 +8978,7 @@ Target_arm::Scan::global(Symbol_table* symtab, && this->reloc_needs_plt_for_ifunc(object, r_type)) target->make_plt_entry(symtab, layout, gsym); - r_type = get_real_reloc_type(r_type); + r_type = target->get_real_reloc_type(r_type); switch (r_type) { case elfcpp::R_ARM_NONE: @@ -9092,8 +9354,7 @@ Target_arm::gc_process_relocs( typedef Target_arm Arm; typedef typename Target_arm::Scan Scan; - gold::gc_process_relocs<32, big_endian, Arm, elfcpp::SHT_REL, Scan, - typename Target_arm::Relocatable_size_for_reloc>( + gold::gc_process_relocs<32, big_endian, Arm, Scan, Classify_reloc>( symtab, layout, this, @@ -9123,7 +9384,6 @@ Target_arm::scan_relocs(Symbol_table* symtab, size_t local_symbol_count, const unsigned char* plocal_symbols) { - typedef typename Target_arm::Scan Scan; if (sh_type == elfcpp::SHT_RELA) { gold_error(_("%s: unsupported RELA reloc section"), @@ -9131,7 +9391,7 @@ Target_arm::scan_relocs(Symbol_table* symtab, return; } - gold::scan_relocs<32, big_endian, Target_arm, elfcpp::SHT_REL, Scan>( + gold::scan_relocs<32, big_endian, Target_arm, Scan, Classify_reloc>( symtab, layout, this, @@ -9326,11 +9586,11 @@ template inline bool Target_arm::Relocate::relocate( const Relocate_info<32, big_endian>* relinfo, + unsigned int, Target_arm* target, Output_section* output_section, size_t relnum, - const elfcpp::Rel<32, big_endian>& rel, - unsigned int r_type, + const unsigned char* preloc, const Sized_symbol<32>* gsym, const Symbol_value<32>* psymval, unsigned char* view, @@ -9342,7 +9602,9 @@ Target_arm::Relocate::relocate( typedef Arm_relocate_functions Arm_relocate_functions; - r_type = get_real_reloc_type(r_type); + const elfcpp::Rel<32, big_endian> rel(preloc); + unsigned int r_type = elfcpp::elf_r_type<32>(rel.get_r_info()); + r_type = target->get_real_reloc_type(r_type); const Arm_reloc_property* reloc_property = arm_reloc_property_table->get_implemented_static_reloc_property(r_type); if (reloc_property == NULL) @@ -10029,8 +10291,8 @@ Target_arm::relocate_section( } } - gold::relocate_section<32, big_endian, Target_arm, elfcpp::SHT_REL, - Arm_relocate, gold::Default_comdat_behavior>( + gold::relocate_section<32, big_endian, Target_arm, Arm_relocate, + gold::Default_comdat_behavior, Classify_reloc>( relinfo, this, prelocs, @@ -10048,11 +10310,13 @@ Target_arm::relocate_section( template unsigned int -Target_arm::Relocatable_size_for_reloc::get_size_for_reloc( +Target_arm::Classify_reloc::get_size_for_reloc( unsigned int r_type, Relobj* object) { - r_type = get_real_reloc_type(r_type); + Target_arm* arm_target = + Target_arm::default_target(); + r_type = arm_target->get_real_reloc_type(r_type); const Arm_reloc_property* arp = arm_reloc_property_table->get_implemented_static_reloc_property(r_type); if (arp != NULL) @@ -10085,13 +10349,12 @@ Target_arm::scan_relocatable_relocs( const unsigned char* plocal_symbols, Relocatable_relocs* rr) { - gold_assert(sh_type == elfcpp::SHT_REL); + typedef Arm_scan_relocatable_relocs + Scan_relocatable_relocs; - typedef Arm_scan_relocatable_relocs Scan_relocatable_relocs; + gold_assert(sh_type == elfcpp::SHT_REL); - gold::scan_relocatable_relocs<32, big_endian, elfcpp::SHT_REL, - Scan_relocatable_relocs>( + gold::scan_relocatable_relocs<32, big_endian, Scan_relocatable_relocs>( symtab, layout, object, @@ -10105,6 +10368,44 @@ Target_arm::scan_relocatable_relocs( rr); } +// Scan the relocs for --emit-relocs. + +template +void +Target_arm::emit_relocs_scan(Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, big_endian>* object, + unsigned int data_shndx, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + size_t local_symbol_count, + const unsigned char* plocal_syms, + Relocatable_relocs* rr) +{ + typedef gold::Default_classify_reloc + Classify_reloc; + typedef gold::Default_emit_relocs_strategy + Emit_relocs_strategy; + + gold_assert(sh_type == elfcpp::SHT_REL); + + gold::scan_relocatable_relocs<32, big_endian, Emit_relocs_strategy>( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_syms, + rr); +} + // Emit relocations for a section. template @@ -10116,7 +10417,6 @@ Target_arm::relocate_relocs( size_t reloc_count, Output_section* output_section, typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section, - const Relocatable_relocs* rr, unsigned char* view, Arm_address view_address, section_size_type view_size, @@ -10125,13 +10425,12 @@ Target_arm::relocate_relocs( { gold_assert(sh_type == elfcpp::SHT_REL); - gold::relocate_relocs<32, big_endian, elfcpp::SHT_REL>( + gold::relocate_relocs<32, big_endian, Classify_reloc>( relinfo, prelocs, reloc_count, output_section, offset_in_output_section, - rr, view, view_address, view_size, @@ -10441,17 +10740,15 @@ Target_arm::do_dynsym_value(const Symbol* gsym) const // template unsigned int -Target_arm::get_real_reloc_type(unsigned int r_type) +Target_arm::get_real_reloc_type(unsigned int r_type) const { switch (r_type) { case elfcpp::R_ARM_TARGET1: - // This is either R_ARM_ABS32 or R_ARM_REL32; - return elfcpp::R_ARM_ABS32; + return this->target1_reloc_; case elfcpp::R_ARM_TARGET2: - // This can be any reloc type but usually is R_ARM_GOT_PREL - return elfcpp::R_ARM_GOT_PREL; + return this->target2_reloc_; default: return r_type; @@ -10544,7 +10841,14 @@ Target_arm::do_adjust_elf_header( e_ident[elfcpp::EI_OSABI] = 0; e_ident[elfcpp::EI_ABIVERSION] = 0; - // FIXME: Do EF_ARM_BE8 adjustment. + // Do EF_ARM_BE8 adjustment. + if (parameters->options().be8() && !big_endian) + gold_error("BE8 images only valid in big-endian mode."); + if (parameters->options().be8()) + { + flags |= elfcpp::EF_ARM_BE8; + this->set_processor_specific_flags(flags); + } // If we're working in EABI_VER5, set the hard/soft float ABI flags // as appropriate. @@ -10563,6 +10867,7 @@ Target_arm::do_adjust_elf_header( } elfcpp::Ehdr_write<32, big_endian> oehdr(view); oehdr.put_e_ident(e_ident); + oehdr.put_e_flags(this->processor_specific_flags()); } // do_make_elf_object to override the same function in the base class. @@ -10759,6 +11064,24 @@ Target_arm::tag_cpu_arch_combine( T(V7E_M), // V6S_M. T(V7E_M) // V7E_M. }; + static const int v8[] = + { + T(V8), // PRE_V4. + T(V8), // V4. + T(V8), // V4T. + T(V8), // V5T. + T(V8), // V5TE. + T(V8), // V5TEJ. + T(V8), // V6. + T(V8), // V6KZ. + T(V8), // V6T2. + T(V8), // V6K. + T(V8), // V7. + T(V8), // V6_M. + T(V8), // V6S_M. + T(V8), // V7E_M. + T(V8) // V8. + }; static const int v4t_plus_v6_m[] = { -1, // PRE_V4. @@ -10775,6 +11098,7 @@ Target_arm::tag_cpu_arch_combine( T(V6_M), // V6_M. T(V6S_M), // V6S_M. T(V7E_M), // V7E_M. + T(V8), // V8. T(V4T_PLUS_V6_M) // V4T plus V6_M. }; static const int* comb[] = @@ -10785,6 +11109,7 @@ Target_arm::tag_cpu_arch_combine( v6_m, v6s_m, v7e_m, + v8, // Pseudo-architecture. v4t_plus_v6_m }; @@ -10882,7 +11207,8 @@ Target_arm::tag_cpu_name_value(unsigned int value) "ARM v7", "ARM v6-M", "ARM v6S-M", - "ARM v7E-M" + "ARM v7E-M", + "ARM v8" }; const size_t name_table_size = sizeof(name_table) / sizeof(name_table[0]); @@ -10908,7 +11234,7 @@ Target_arm::attributes_accept_div(int arch, int profile, { case 0: // Integer divide allowed if instruction contained in - // archetecture. + // architecture. if (arch == elfcpp::TAG_CPU_ARCH_V7 && (profile == 'R' || profile == 'M')) return true; else if (arch >= elfcpp::TAG_CPU_ARCH_V7E_M) @@ -11354,7 +11680,7 @@ Target_arm::merge_object_attributes( if (in_attr[elfcpp::Tag_MPextension_use].int_value() != in_attr[i].int_value()) { - gold_error(_("%s has has both the current and legacy " + gold_error(_("%s has both the current and legacy " "Tag_MPextension_use attributes"), name); } @@ -11814,6 +12140,7 @@ Target_arm::scan_reloc_section_for_stubs( const Symbol_value<32> *psymval; bool is_defined_in_discarded_section; unsigned int shndx; + const Symbol* gsym = NULL; if (r_sym < local_count) { sym = NULL; @@ -11837,6 +12164,8 @@ Target_arm::scan_reloc_section_for_stubs( if (!is_defined_in_discarded_section) { typedef Sized_relobj_file<32, big_endian> ObjType; + if (psymval->is_section_symbol()) + symval.set_is_section_symbol(); typename ObjType::Compute_final_local_value_status status = arm_object->compute_final_local_value(r_sym, psymval, &symval, relinfo->symtab); @@ -11864,7 +12193,6 @@ Target_arm::scan_reloc_section_for_stubs( } else { - const Symbol* gsym; gsym = arm_object->global_symbol(r_sym); gold_assert(gsym != NULL); if (gsym->is_forwarder()) @@ -11905,11 +12233,11 @@ Target_arm::scan_reloc_section_for_stubs( Symbol_value<32> symval2; if (is_defined_in_discarded_section) { + std::string name = arm_object->section_name(relinfo->data_shndx); + if (comdat_behavior == CB_UNDETERMINED) - { - std::string name = arm_object->section_name(relinfo->data_shndx); comdat_behavior = default_comdat_behavior.get(name.c_str()); - } + if (comdat_behavior == CB_PRETEND) { // FIXME: This case does not work for global symbols. @@ -11919,7 +12247,7 @@ Target_arm::scan_reloc_section_for_stubs( // script. bool found; typename elfcpp::Elf_types<32>::Elf_Addr value = - arm_object->map_to_kept_section(shndx, &found); + arm_object->map_to_kept_section(shndx, name, &found); if (found) symval2.set_output_value(value + psymval->input_value()); else @@ -11927,10 +12255,8 @@ Target_arm::scan_reloc_section_for_stubs( } else { - if (comdat_behavior == CB_WARNING) - gold_warning_at_location(relinfo, i, offset, - _("relocation refers to discarded " - "section")); + if (comdat_behavior == CB_ERROR) + issue_discarded_error(relinfo, i, offset, r_sym, gsym); symval2.set_output_value(0); } symval2.set_no_output_symtab_entry(); @@ -12263,10 +12589,9 @@ Target_arm::relocate_stub( elfcpp::Rel_write<32, big_endian> reloc_write(reloc_buffer); reloc_write.put_r_offset(reloc_offset); reloc_write.put_r_info(elfcpp::elf_r_info<32>(0, r_type)); - elfcpp::Rel<32, big_endian> rel(reloc_buffer); - relocate.relocate(relinfo, this, output_section, - this->fake_relnum_for_stubs, rel, r_type, + relocate.relocate(relinfo, elfcpp::SHT_REL, this, output_section, + this->fake_relnum_for_stubs, reloc_buffer, NULL, &symval, view + reloc_offset, address + reloc_offset, reloc_size); } @@ -12468,7 +12793,7 @@ Target_arm::scan_span_for_cortex_a8_erratum( Arm_address target = (pc_for_insn + offset) | (is_blx ? 0 : 1); - // Add a new stub if destination address in in the same page. + // Add a new stub if destination address is in the same page. if (((address + i) & ~0xfffU) == (target & ~0xfffU)) { Cortex_a8_stub* stub = @@ -12514,7 +12839,7 @@ Target_arm::apply_cortex_a8_workaround( // branch to the stub. We use the THUMB-2 encoding here. upper_insn = 0xf000U; lower_insn = 0xb800U; - // Fall through + // Fall through. case arm_stub_a8_veneer_b: case arm_stub_a8_veneer_bl: case arm_stub_a8_veneer_blx: @@ -12570,7 +12895,7 @@ Target_arm::fix_exidx_coverage( const Task* task) { // We need to look at all the input sections in output in ascending - // order of of output address. We do that by building a sorted list + // order of output address. We do that by building a sorted list // of output sections by addresses. Then we looks at the output sections // in order. The input sections in an output section are already sorted // by addresses within the output section. @@ -12728,7 +13053,9 @@ const Target::Target_info Target_arm_nacl::arm_nacl_info = 0, // large_common_section_flags ".ARM.attributes", // attributes_section "aeabi", // attributes_vendor - "_start" // entry_symbol_name + "_start", // entry_symbol_name + 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; template