X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Farm.cc;h=c47b00224cc7c0c15c28ae69a9d2893684e58caa;hb=a6b71f422b2a4c1dae639064945bc8697528c57b;hp=8485ab348433d0f5c51c45c1314598244799bd41;hpb=f12d1e8a660c34ce3098da788ac01d067d6ccbab;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/arm.cc b/gold/arm.cc index 8485ab3484..c47b00224c 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1,6 +1,6 @@ // arm.cc -- arm target support for gold. -// Copyright (C) 2009-2014 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; @@ -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 { @@ -2119,8 +2122,8 @@ class Target_arm : public Sized_target<32, big_endian> Target_arm(const Target::Target_info* info = &arm_info) : Sized_target<32, big_endian>(info), - got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL), - copy_relocs_(elfcpp::R_ARM_COPY), + got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL), + rel_dyn_(NULL), rel_irelative_(NULL), copy_relocs_(elfcpp::R_ARM_COPY), got_mod_index_offset_(-1U), tls_base_symbol_defined_(false), stub_tables_(), stub_factory_(Stub_factory::get_instance()), should_force_pic_veneer_(false), @@ -2258,6 +2261,18 @@ class Target_arm : public Sized_target<32, big_endian> uint64_t do_dynsym_value(const Symbol*) const; + // Return the plt address for globals. Since we have irelative plt entries, + // address calculation is not as straightforward as plt_address + plt_offset. + uint64_t + do_plt_address_for_global(const Symbol* gsym) const + { return this->plt_section()->address_for_global(gsym); } + + // Return the plt address for locals. Since we have irelative plt entries, + // address calculation is not as straightforward as plt_address + plt_offset. + uint64_t + do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const + { return this->plt_section()->address_for_local(relobj, symndx); } + // Relocate a section. void relocate_section(const Relocate_info<32, big_endian>*, @@ -2286,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>*, @@ -2295,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, @@ -2357,6 +2386,10 @@ class Target_arm : public Sized_target<32, big_endian> unsigned int plt_entry_size() const; + // Get the section to use for IRELATIVE relocations, create it if necessary. + Reloc_section* + rel_irelative_section(Layout*); + // Map platform-specific reloc types static unsigned int get_real_reloc_type(unsigned int r_type); @@ -2448,8 +2481,11 @@ class Target_arm : public Sized_target<32, big_endian> protected: // Make the PLT-generator object. Output_data_plt_arm* - make_data_plt(Layout* layout, Output_data_space* got_plt) - { return this->do_make_data_plt(layout, got_plt); } + make_data_plt(Layout* layout, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + { return this->do_make_data_plt(layout, got, got_plt, got_irelative); } // Make an ELF object. Object* @@ -2530,9 +2566,18 @@ class Target_arm : public Sized_target<32, big_endian> do_define_standard_symbols(Symbol_table*, Layout*); virtual Output_data_plt_arm* - do_make_data_plt(Layout* layout, Output_data_space* got_plt) + do_make_data_plt(Layout* layout, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) { - return new Output_data_plt_arm_standard(layout, got_plt); + gold_assert(got_plt != NULL && got_irelative != NULL); + 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); } private: @@ -2602,6 +2647,9 @@ class Target_arm : public Sized_target<32, big_endian> if (sym->is_undefined() && !parameters->options().shared()) return false; + if (sym->type() == elfcpp::STT_GNU_IFUNC) + return true; + return (!parameters->doing_static_link() && (sym->type() == elfcpp::STT_FUNC || sym->type() == elfcpp::STT_ARM_TFUNC) @@ -2613,6 +2661,11 @@ class Target_arm : public Sized_target<32, big_endian> inline bool possible_function_pointer_reloc(unsigned int r_type); + // Whether a plt entry is needed for ifunc. + bool + reloc_needs_plt_for_ifunc(Sized_relobj_file<32, big_endian>*, + unsigned int r_type); + // Whether we have issued an error about a non-PIC compilation. bool issued_non_pic_error_; }; @@ -2637,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 @@ -2692,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*); }; @@ -2718,10 +2779,20 @@ class Target_arm : public Sized_target<32, big_endian> return this->got_plt_; } + // Create the PLT section. + void + make_plt_section(Symbol_table* symtab, Layout* layout); + // Create a PLT entry for a global symbol. void make_plt_entry(Symbol_table*, Layout*, Symbol*); + // Create a PLT entry for a local STT_GNU_IFUNC symbol. + void + make_local_ifunc_plt_entry(Symbol_table*, Layout*, + Sized_relobj_file<32, big_endian>* relobj, + unsigned int local_sym_index); + // Define the _TLS_MODULE_BASE_ symbol in the TLS segment. void define_tls_base_symbol(Symbol_table*, Layout*); @@ -2764,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)); } @@ -2903,8 +2976,12 @@ class Target_arm : public Sized_target<32, big_endian> Output_data_plt_arm* plt_; // The GOT PLT section. Output_data_space* got_plt_; + // The GOT section for IRELATIVE relocations. + Output_data_space* got_irelative_; // The dynamic reloc section. Reloc_section* rel_dyn_; + // The section to use for IRELATIVE relocs. + Reloc_section* rel_irelative_; // Relocs saved to avoid a COPY reloc. Copy_relocs copy_relocs_; // Offset of the GOT entry for the TLS module index. @@ -2951,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 @@ -4244,6 +4322,15 @@ Target_arm::got_section(Symbol_table* symtab, Layout* layout) elfcpp::STB_LOCAL, elfcpp::STV_HIDDEN, 0, false, false); + + // If there are any IRELATIVE relocations, they get GOT entries + // in .got.plt after the jump slot entries. + this->got_irelative_ = new Output_data_space(4, "** GOT IRELATIVE PLT"); + layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), + this->got_irelative_, + got_order, is_got_relro); + } return this->got_; } @@ -4257,14 +4344,43 @@ Target_arm::rel_dyn_section(Layout* layout) if (this->rel_dyn_ == NULL) { gold_assert(layout != NULL); + // Create both relocation sections in the same place, so as to ensure + // their relative order in the output section. this->rel_dyn_ = new Reloc_section(parameters->options().combreloc()); + this->rel_irelative_ = new Reloc_section(false); layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, elfcpp::SHF_ALLOC, this->rel_dyn_, ORDER_DYNAMIC_RELOCS, false); + layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->rel_irelative_, + ORDER_DYNAMIC_RELOCS, false); } return this->rel_dyn_; } + +// Get the section to use for IRELATIVE relocs, creating it if necessary. These +// go in .rela.dyn, but only after all other dynamic relocations. They need to +// follow the other dynamic relocations so that they can refer to global +// variables initialized by those relocs. + +template +typename Target_arm::Reloc_section* +Target_arm::rel_irelative_section(Layout* layout) +{ + if (this->rel_irelative_ == NULL) + { + // Delegate the creation to rel_dyn_section so as to ensure their order in + // the output section. + this->rel_dyn_section(layout); + gold_assert(this->rel_irelative_ != NULL + && (this->rel_dyn_->output_section() + == this->rel_irelative_->output_section())); + } + return this->rel_irelative_; +} + + // Insn_template methods. // Return byte size of an instruction template. @@ -4458,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()) @@ -4466,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(); } @@ -4475,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(); } @@ -6171,16 +6288,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); @@ -7221,24 +7331,80 @@ template class Output_data_plt_arm : public Output_section_data { public: + // Unlike aarch64, which records symbol value in "addend" field of relocations + // and could be done at the same time an IRelative reloc is created for the + // symbol, arm puts the symbol value into "GOT" table, which, however, is + // issued later in Output_data_plt_arm::do_write(). So we have a struct here + // to keep necessary symbol information for later use in do_write. We usually + // have only a very limited number of ifuncs, so the extra data required here + // is also limited. + + struct IRelative_data + { + IRelative_data(Sized_symbol<32>* sized_symbol) + : symbol_is_global_(true) + { + u_.global = sized_symbol; + } + + IRelative_data(Sized_relobj_file<32, big_endian>* relobj, + unsigned int index) + : symbol_is_global_(false) + { + u_.local.relobj = relobj; + u_.local.index = index; + } + + union + { + Sized_symbol<32>* global; + + struct + { + Sized_relobj_file<32, big_endian>* relobj; + unsigned int index; + } local; + } u_; + + bool symbol_is_global_; + }; + typedef Output_data_reloc Reloc_section; - Output_data_plt_arm(Layout*, uint64_t addralign, Output_data_space*); + Output_data_plt_arm(Layout* layout, uint64_t addralign, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative); // Add an entry to the PLT. void - add_entry(Symbol* gsym); + add_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym); + + // Add the relocation for a plt entry. + void + add_relocation(Symbol_table* symtab, Layout* layout, + Symbol* gsym, unsigned int got_offset); + + // Add an entry to the PLT for a local STT_GNU_IFUNC symbol. + unsigned int + add_local_ifunc_entry(Symbol_table* symtab, Layout*, + Sized_relobj_file<32, big_endian>* relobj, + unsigned int local_sym_index); // Return the .rel.plt section data. const Reloc_section* rel_plt() const { return this->rel_; } + // Return the PLT relocation container for IRELATIVE. + Reloc_section* + rel_irelative(Symbol_table*, Layout*); + // Return the number of PLT entries. unsigned int entry_count() const - { return this->count_; } + { return this->count_ + this->irelative_count_; } // Return the offset of the first non-reserved PLT entry. unsigned int @@ -7250,6 +7416,14 @@ class Output_data_plt_arm : public Output_section_data get_plt_entry_size() const { return this->do_get_plt_entry_size(); } + // Return the PLT address for globals. + uint32_t + address_for_global(const Symbol*) const; + + // Return the PLT address for locals. + uint32_t + address_for_local(const Relobj*, unsigned int symndx) const; + protected: // Fill in the first PLT entry. void @@ -7298,19 +7472,37 @@ class Output_data_plt_arm : public Output_section_data set_final_data_size() { this->set_data_size(this->first_plt_entry_offset() - + this->count_ * this->get_plt_entry_size()); + + ((this->count_ + this->irelative_count_) + * this->get_plt_entry_size())); } // Write out the PLT data. void do_write(Output_file*); + // Record irelative symbol data. + void insert_irelative_data(const IRelative_data& idata) + { irelative_data_vec_.push_back(idata); } + // The reloc section. Reloc_section* rel_; + // The IRELATIVE relocs, if necessary. These must follow the + // regular PLT relocations. + Reloc_section* irelative_rel_; + // The .got section. + Arm_output_data_got* got_; // The .got.plt section. Output_data_space* got_plt_; + // The part of the .got.plt section used for IRELATIVE relocs. + Output_data_space* got_irelative_; // The number of PLT entries. unsigned int count_; + // Number of PLT entries with R_ARM_IRELATIVE relocs. These + // follow the regular PLT entries. + unsigned int irelative_count_; + // Vector for irelative data. + typedef std::vector IRelative_data_vec; + IRelative_data_vec irelative_data_vec_; }; // Create the PLT section. The ordinary .got section is an argument, @@ -7318,10 +7510,14 @@ class Output_data_plt_arm : public Output_section_data // section just for PLT entries. template -Output_data_plt_arm::Output_data_plt_arm(Layout* layout, - uint64_t addralign, - Output_data_space* got_plt) - : Output_section_data(addralign), got_plt_(got_plt), count_(0) +Output_data_plt_arm::Output_data_plt_arm( + Layout* layout, uint64_t addralign, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_section_data(addralign), irelative_rel_(NULL), + got_(got), got_plt_(got_plt), got_irelative_(got_irelative), + count_(0), irelative_count_(0) { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, @@ -7340,40 +7536,210 @@ Output_data_plt_arm::do_adjust_output_section(Output_section* os) template void -Output_data_plt_arm::add_entry(Symbol* gsym) +Output_data_plt_arm::add_entry(Symbol_table* symtab, + Layout* layout, + Symbol* gsym) { gold_assert(!gsym->has_plt_offset()); - // Note that when setting the PLT offset we skip the initial - // reserved PLT entry. - gsym->set_plt_offset((this->count_) * this->get_plt_entry_size() - + this->first_plt_entry_offset()); + unsigned int* entry_count; + Output_section_data_build* got; + + // We have 2 different types of plt entry here, normal and ifunc. + + // For normal plt, the offset begins with first_plt_entry_offset(20), and the + // 1st entry offset would be 20, the second 32, third 44 ... etc. + + // For ifunc plt, the offset begins with 0. So the first offset would 0, + // second 12, third 24 ... etc. - ++this->count_; + // IFunc plt entries *always* come after *normal* plt entries. - section_offset_type got_offset = this->got_plt_->current_data_size(); + // Notice, when computing the plt address of a certain symbol, "plt_address + + // plt_offset" is no longer correct. Use target->plt_address_for_global() or + // target->plt_address_for_local() instead. + + int begin_offset = 0; + if (gsym->type() == elfcpp::STT_GNU_IFUNC + && gsym->can_use_relative_reloc(false)) + { + entry_count = &this->irelative_count_; + got = this->got_irelative_; + // For irelative plt entries, offset is relative to the end of normal plt + // entries, so it starts from 0. + begin_offset = 0; + // Record symbol information. + this->insert_irelative_data( + IRelative_data(symtab->get_sized_symbol<32>(gsym))); + } + else + { + entry_count = &this->count_; + got = this->got_plt_; + // Note that for normal plt entries, when setting the PLT offset we skip + // the initial reserved PLT entry. + begin_offset = this->first_plt_entry_offset(); + } + + gsym->set_plt_offset(begin_offset + + (*entry_count) * this->get_plt_entry_size()); + + ++(*entry_count); + + section_offset_type got_offset = got->current_data_size(); // Every PLT entry needs a GOT entry which points back to the PLT // entry (this will be changed by the dynamic linker, normally // lazily when the function is called). - this->got_plt_->set_current_data_size(got_offset + 4); + got->set_current_data_size(got_offset + 4); // Every PLT entry needs a reloc. - gsym->set_needs_dynsym_entry(); - this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_, - got_offset); + this->add_relocation(symtab, layout, gsym, got_offset); // Note that we don't need to save the symbol. The contents of the // PLT are independent of which symbols are used. The symbols only // appear in the relocations. } +// Add an entry to the PLT for a local STT_GNU_IFUNC symbol. Return +// the PLT offset. + +template +unsigned int +Output_data_plt_arm::add_local_ifunc_entry( + Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, big_endian>* relobj, + unsigned int local_sym_index) +{ + this->insert_irelative_data(IRelative_data(relobj, local_sym_index)); + + // Notice, when computingthe plt entry address, "plt_address + plt_offset" is + // no longer correct. Use target->plt_address_for_local() instead. + unsigned int plt_offset = this->irelative_count_ * this->get_plt_entry_size(); + ++this->irelative_count_; + + section_offset_type got_offset = this->got_irelative_->current_data_size(); + + // Every PLT entry needs a GOT entry which points back to the PLT + // entry. + this->got_irelative_->set_current_data_size(got_offset + 4); + + + // Every PLT entry needs a reloc. + Reloc_section* rel = this->rel_irelative(symtab, layout); + rel->add_symbolless_local_addend(relobj, local_sym_index, + elfcpp::R_ARM_IRELATIVE, + this->got_irelative_, got_offset); + return plt_offset; +} + + +// Add the relocation for a PLT entry. + +template +void +Output_data_plt_arm::add_relocation( + Symbol_table* symtab, Layout* layout, Symbol* gsym, unsigned int got_offset) +{ + if (gsym->type() == elfcpp::STT_GNU_IFUNC + && gsym->can_use_relative_reloc(false)) + { + Reloc_section* rel = this->rel_irelative(symtab, layout); + rel->add_symbolless_global_addend(gsym, elfcpp::R_ARM_IRELATIVE, + this->got_irelative_, got_offset); + } + else + { + gsym->set_needs_dynsym_entry(); + this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_, + got_offset); + } +} + + +// Create the irelative relocation data. + +template +typename Output_data_plt_arm::Reloc_section* +Output_data_plt_arm::rel_irelative(Symbol_table* symtab, + Layout* layout) +{ + if (this->irelative_rel_ == NULL) + { + // Since irelative relocations goes into 'rel.dyn', we delegate the + // creation of irelative_rel_ to where rel_dyn section gets created. + Target_arm* arm_target = + Target_arm::default_target(); + this->irelative_rel_ = arm_target->rel_irelative_section(layout); + + // Make sure we have a place for the TLSDESC relocations, in + // case we see any later on. + // this->rel_tlsdesc(layout); + if (parameters->doing_static_link()) + { + // A statically linked executable will only have a .rel.plt section to + // hold R_ARM_IRELATIVE relocs for STT_GNU_IFUNC symbols. The library + // will use these symbols to locate the IRELATIVE relocs at program + // startup time. + symtab->define_in_output_data("__rel_iplt_start", NULL, + Symbol_table::PREDEFINED, + this->irelative_rel_, 0, 0, + elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, 0, false, true); + symtab->define_in_output_data("__rel_iplt_end", NULL, + Symbol_table::PREDEFINED, + this->irelative_rel_, 0, 0, + elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, 0, true, true); + } + } + return this->irelative_rel_; +} + + +// Return the PLT address for a global symbol. + +template +uint32_t +Output_data_plt_arm::address_for_global(const Symbol* gsym) const +{ + uint64_t begin_offset = 0; + if (gsym->type() == elfcpp::STT_GNU_IFUNC + && gsym->can_use_relative_reloc(false)) + { + begin_offset = (this->first_plt_entry_offset() + + this->count_ * this->get_plt_entry_size()); + } + return this->address() + begin_offset + gsym->plt_offset(); +} + + +// Return the PLT address for a local symbol. These are always +// IRELATIVE relocs. + +template +uint32_t +Output_data_plt_arm::address_for_local( + const Relobj* object, + unsigned int r_sym) const +{ + return (this->address() + + this->first_plt_entry_offset() + + this->count_ * this->get_plt_entry_size() + + object->local_plt_offset(r_sym)); +} + + template class Output_data_plt_arm_standard : public Output_data_plt_arm { public: - Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt) - : Output_data_plt_arm(layout, 4, got_plt) + Output_data_plt_arm_standard(Layout* layout, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_data_plt_arm(layout, 4, got, got_plt, got_irelative) { } protected: @@ -7382,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. @@ -7432,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] - . @@ -7441,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 -const uint32_t Output_data_plt_arm_standard::plt_entry[3] = +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_short::plt_entry[3] = { 0xe28fc600, // add ip, pc, #0xNN00000 0xe28cca00, // add ip, ip, #0xNN000 @@ -7452,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, @@ -7461,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); @@ -7471,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. @@ -7485,8 +7929,11 @@ Output_data_plt_arm::do_write(Output_file* of) unsigned char* const oview = of->get_output_view(offset, oview_size); const off_t got_file_offset = this->got_plt_->offset(); + gold_assert(got_file_offset + this->got_plt_->data_size() + == this->got_irelative_->offset()); const section_size_type got_size = - convert_to_section_size_type(this->got_plt_->data_size()); + convert_to_section_size_type(this->got_plt_->data_size() + + this->got_irelative_->data_size()); unsigned char* const got_view = of->get_output_view(got_file_offset, got_size); unsigned char* pov = oview; @@ -7505,7 +7952,8 @@ Output_data_plt_arm::do_write(Output_file* of) unsigned int plt_offset = this->first_plt_entry_offset(); unsigned int got_offset = 12; - const unsigned int count = this->count_; + const unsigned int count = this->count_ + this->irelative_count_; + gold_assert(this->irelative_count_ == this->irelative_data_vec_.size()); for (unsigned int i = 0; i < count; ++i, @@ -7518,8 +7966,33 @@ Output_data_plt_arm::do_write(Output_file* of) this->fill_plt_entry(pov, got_address, plt_address, got_offset, plt_offset); - // Set the entry in the GOT. - elfcpp::Swap<32, big_endian>::writeval(got_pov, plt_address); + Arm_address value; + if (i < this->count_) + { + // For non-irelative got entries, the value is the beginning of plt. + value = plt_address; + } + else + { + // For irelative got entries, the value is the (global/local) symbol + // address. + const IRelative_data& idata = + this->irelative_data_vec_[i - this->count_]; + if (idata.symbol_is_global_) + { + // Set the entry in the GOT for irelative symbols. The content is + // the address of the ifunc, not the address of plt start. + const Sized_symbol<32>* sized_symbol = idata.u_.global; + gold_assert(sized_symbol->type() == elfcpp::STT_GNU_IFUNC); + value = sized_symbol->value(); + } + else + { + value = idata.u_.local.relobj->local_symbol_value( + idata.u_.local.index, 0); + } + } + elfcpp::Swap<32, big_endian>::writeval(got_pov, value); } gold_assert(static_cast(pov - oview) == oview_size); @@ -7529,6 +8002,7 @@ Output_data_plt_arm::do_write(Output_file* of) of->write_output_view(got_file_offset, got_size, got_view); } + // Create a PLT entry for a global symbol. template @@ -7539,21 +8013,66 @@ Target_arm::make_plt_entry(Symbol_table* symtab, Layout* layout, if (gsym->has_plt_offset()) return; + if (this->plt_ == NULL) + this->make_plt_section(symtab, layout); + + this->plt_->add_entry(symtab, layout, gsym); +} + + +// Create the PLT section. +template +void +Target_arm::make_plt_section( + Symbol_table* symtab, Layout* layout) +{ if (this->plt_ == NULL) { - // Create the GOT sections first. + // Create the GOT section first. this->got_section(symtab, layout); - this->plt_ = this->make_data_plt(layout, this->got_plt_); + // GOT for irelatives is create along with got.plt. + gold_assert(this->got_ != NULL + && this->got_plt_ != NULL + && this->got_irelative_ != NULL); + this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_, + this->got_irelative_); layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), this->plt_, ORDER_PLT, false); + symtab->define_in_output_data("$a", NULL, + Symbol_table::PREDEFINED, + this->plt_, + 0, 0, elfcpp::STT_NOTYPE, + elfcpp::STB_LOCAL, + elfcpp::STV_DEFAULT, 0, + false, false); } - this->plt_->add_entry(gsym); } + +// Make a PLT entry for a local STT_GNU_IFUNC symbol. + +template +void +Target_arm::make_local_ifunc_plt_entry( + Symbol_table* symtab, Layout* layout, + Sized_relobj_file<32, big_endian>* relobj, + unsigned int local_sym_index) +{ + if (relobj->local_has_plt_offset(local_sym_index)) + return; + if (this->plt_ == NULL) + this->make_plt_section(symtab, layout); + unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout, + relobj, + local_sym_index); + relobj->set_local_plt_offset(local_sym_index, plt_offset); +} + + // Return the number of entries in the PLT. template @@ -7823,6 +8342,7 @@ Target_arm::Scan::check_non_pic(Relobj* object, case elfcpp::R_ARM_JUMP_SLOT: case elfcpp::R_ARM_ABS32: case elfcpp::R_ARM_ABS32_NOI: + case elfcpp::R_ARM_IRELATIVE: case elfcpp::R_ARM_PC24: // FIXME: The following 3 types are not supported by Android's dynamic // linker. @@ -7853,6 +8373,27 @@ Target_arm::Scan::check_non_pic(Relobj* object, } } + +// Return whether we need to make a PLT entry for a relocation of the +// given type against a STT_GNU_IFUNC symbol. + +template +bool +Target_arm::Scan::reloc_needs_plt_for_ifunc( + Sized_relobj_file<32, big_endian>* object, + unsigned int r_type) +{ + int flags = Scan::get_reference_flags(r_type); + if (flags & Symbol::TLS_REF) + { + gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"), + object->name().c_str(), r_type); + return false; + } + return flags != 0; +} + + // Scan a relocation for a local symbol. // FIXME: This only handles a subset of relocation types used by Android // on ARM v5te devices. @@ -7874,6 +8415,15 @@ Target_arm::Scan::local(Symbol_table* symtab, return; r_type = 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; + if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type)) + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym); + } + switch (r_type) { case elfcpp::R_ARM_NONE: @@ -7898,7 +8448,7 @@ Target_arm::Scan::local(Symbol_table* symtab, // we need to add check_non_pic(object, r_type) here. rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE, output_section, data_shndx, - reloc.get_r_offset()); + reloc.get_r_offset(), is_ifunc); } break; @@ -8265,6 +8815,11 @@ Target_arm::Scan::global(Symbol_table* symtab, && strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0) target->got_section(symtab, layout); + // A STT_GNU_IFUNC symbol may require a PLT entry. + if (gsym->type() == elfcpp::STT_GNU_IFUNC + && this->reloc_needs_plt_for_ifunc(object, r_type)) + target->make_plt_entry(symtab, layout, gsym); + r_type = get_real_reloc_type(r_type); switch (r_type) { @@ -8307,6 +8862,24 @@ Target_arm::Scan::global(Symbol_table* symtab, target->copy_reloc(symtab, layout, object, data_shndx, output_section, gsym, reloc); } + else if ((r_type == elfcpp::R_ARM_ABS32 + || r_type == elfcpp::R_ARM_ABS32_NOI) + && gsym->type() == elfcpp::STT_GNU_IFUNC + && gsym->can_use_relative_reloc(false) + && !gsym->is_from_dynobj() + && !gsym->is_undefined() + && !gsym->is_preemptible()) + { + // Use an IRELATIVE reloc for a locally defined STT_GNU_IFUNC + // symbol. This makes a function address in a PIE executable + // match the address in a shared library that it links against. + Reloc_section* rel_irelative = + target->rel_irelative_section(layout); + unsigned int r_type = elfcpp::R_ARM_IRELATIVE; + rel_irelative->add_symbolless_global_addend( + gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset()); + } else if ((r_type == elfcpp::R_ARM_ABS32 || r_type == elfcpp::R_ARM_ABS32_NOI) && gsym->can_use_relative_reloc(false)) @@ -8442,7 +9015,13 @@ Target_arm::Scan::global(Symbol_table* symtab, Arm_output_data_got* got = target->got_section(symtab, layout); if (gsym->final_value_is_known()) - got->add_global(gsym, GOT_TYPE_STANDARD); + { + // For a STT_GNU_IFUNC symbol we want the PLT address. + if (gsym->type() == elfcpp::STT_GNU_IFUNC) + got->add_global_plt(gsym, GOT_TYPE_STANDARD); + else + got->add_global(gsym, GOT_TYPE_STANDARD); + } else { // If this symbol is not fully resolved, we need to add a @@ -8452,12 +9031,29 @@ Target_arm::Scan::global(Symbol_table* symtab, || gsym->is_undefined() || gsym->is_preemptible() || (gsym->visibility() == elfcpp::STV_PROTECTED - && parameters->options().shared())) + && parameters->options().shared()) + || (gsym->type() == elfcpp::STT_GNU_IFUNC + && parameters->options().output_is_position_independent())) got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rel_dyn, elfcpp::R_ARM_GLOB_DAT); else { - if (got->add_global(gsym, GOT_TYPE_STANDARD)) + // For a STT_GNU_IFUNC symbol we want to write the PLT + // offset into the GOT, so that function pointer + // comparisons work correctly. + bool is_new; + if (gsym->type() != elfcpp::STT_GNU_IFUNC) + is_new = got->add_global(gsym, GOT_TYPE_STANDARD); + else + { + is_new = got->add_global_plt(gsym, GOT_TYPE_STANDARD); + // Tell the dynamic linker to use the PLT address + // when resolving relocations. + if (gsym->is_from_dynobj() + && !parameters->options().shared()) + gsym->set_needs_dynsym_value(); + } + if (is_new) rel_dyn->add_global_relative( gsym, elfcpp::R_ARM_RELATIVE, got, gsym->got_offset(GOT_TYPE_STANDARD)); @@ -8600,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, @@ -8631,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"), @@ -8639,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, @@ -8834,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, @@ -8850,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); @@ -8919,8 +9515,7 @@ Target_arm::Relocate::relocate( if (gsym->use_plt_offset(Scan::get_reference_flags(r_type))) { // This uses a PLT, change the symbol value. - symval.set_output_value(target->plt_section()->address() - + gsym->plt_offset()); + symval.set_output_value(target->plt_address_for_global(gsym)); psymval = &symval; } else if (gsym->is_weak_undefined()) @@ -8958,6 +9553,13 @@ Target_arm::Relocate::relocate( elfcpp::Elf_types<32>::Elf_WXword r_info = rel.get_r_info(); unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info); thumb_bit = object->local_symbol_is_thumb_function(r_sym) ? 1 : 0; + + if (psymval->is_ifunc_symbol() && object->local_has_plt_offset(r_sym)) + { + symval.set_output_value( + target->plt_address_for_local(object, r_sym)); + psymval = &symval; + } } } else @@ -9531,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, @@ -9550,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) { @@ -9587,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, @@ -9607,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 @@ -9618,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, @@ -9627,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, @@ -9936,7 +10573,7 @@ uint64_t Target_arm::do_dynsym_value(const Symbol* gsym) const { gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset()); - return this->plt_section()->address() + gsym->plt_offset(); + return this->plt_address_for_global(gsym); } // Map platform-specific relocs to real relocs @@ -10065,6 +10702,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. @@ -10261,6 +10899,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. @@ -10277,6 +10933,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[] = @@ -10287,6 +10944,7 @@ Target_arm::tag_cpu_arch_combine( v6_m, v6s_m, v7e_m, + v8, // Pseudo-architecture. v4t_plus_v6_m }; @@ -10384,7 +11042,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]); @@ -11091,8 +11750,7 @@ Target_arm::scan_reloc_for_stub( if (gsym->use_plt_offset(Scan::get_reference_flags(r_type))) { // This uses a PLT, change the symbol value. - symval.set_output_value(this->plt_section()->address() - + gsym->plt_offset()); + symval.set_output_value(this->plt_address_for_global(gsym)); psymval = &symval; target_is_thumb = false; } @@ -11766,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); } @@ -12195,8 +12852,13 @@ class Target_arm_nacl : public Target_arm protected: virtual Output_data_plt_arm* - do_make_data_plt(Layout* layout, Output_data_space* got_plt) - { return new Output_data_plt_arm_nacl(layout, got_plt); } + do_make_data_plt( + Layout* layout, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + { return new Output_data_plt_arm_nacl( + layout, got, got_plt, got_irelative); } private: static const Target::Target_info arm_nacl_info; @@ -12226,15 +12888,20 @@ 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 class Output_data_plt_arm_nacl : public Output_data_plt_arm { public: - Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt) - : Output_data_plt_arm(layout, 16, got_plt) + Output_data_plt_arm_nacl( + Layout* layout, + Arm_output_data_got* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_data_plt_arm(layout, 16, got, got_plt, got_irelative) { } protected: