X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Farm.cc;h=ed13c8709cc4847bdf35dcab951e5ddf21b335c2;hb=9ef9e6a6a0dd8f948708cb67c9afcfd0be40cb0a;hp=621b28e4c26f18cd37cf31e4a022d2bc8f1366a3;hpb=2bca03770d4d219b4e29d43754a9d95a4152255a;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/arm.cc b/gold/arm.cc index 621b28e4c2..ed13c8709c 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-2016 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; @@ -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 { @@ -2298,6 +2301,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 +2325,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, @@ -2555,7 +2572,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 +2690,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 +2742,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 +2835,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)); } @@ -2997,7 +3028,8 @@ 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 }; // Arm relocate functions class @@ -4542,7 +4574,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 +4582,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 +4591,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(); } @@ -7715,29 +7748,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. @@ -7765,7 +7783,7 @@ 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]); // Last word in first PLT entry is &GOT[0] - . @@ -7774,9 +7792,39 @@ Output_data_plt_arm_standard::do_fill_first_plt_entry( } // 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 @@ -7785,7 +7833,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, @@ -7794,8 +7842,9 @@ 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); @@ -7804,6 +7853,68 @@ Output_data_plt_arm_standard::do_fill_plt_entry( 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); + elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); + uint32_t plt_insn1 = plt_entry[1] | ((offset >> 20) & 0xff); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1); + uint32_t plt_insn2 = plt_entry[2] | ((offset >> 12) & 0xff); + elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); + uint32_t plt_insn3 = plt_entry[3] | (offset & 0xfff); + elfcpp::Swap<32, big_endian>::writeval(pov + 12, plt_insn3); +} + // Write out the PLT. This uses the hand-coded instructions above, // and adjusts them as needed. This is all specified by the arm ELF // Processor Supplement. @@ -9085,8 +9196,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, @@ -9116,7 +9226,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"), @@ -9124,7 +9233,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, @@ -9319,11 +9428,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, @@ -9335,6 +9444,8 @@ Target_arm::Relocate::relocate( typedef Arm_relocate_functions Arm_relocate_functions; + const elfcpp::Rel<32, big_endian> rel(preloc); + unsigned int r_type = elfcpp::elf_r_type<32>(rel.get_r_info()); r_type = get_real_reloc_type(r_type); const Arm_reloc_property* reloc_property = arm_reloc_property_table->get_implemented_static_reloc_property(r_type); @@ -10022,8 +10133,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, @@ -10041,7 +10152,7 @@ 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) { @@ -10078,13 +10189,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, @@ -10098,6 +10208,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 @@ -10109,7 +10257,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, @@ -10118,13 +10265,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, @@ -12278,10 +12424,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); } @@ -12743,7 +12888,8 @@ 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 }; template