aboutsummaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch')
-rw-r--r--meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch1004
1 files changed, 0 insertions, 1004 deletions
diff --git a/meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch b/meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch
deleted file mode 100644
index dcac308bcc..0000000000
--- a/meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch
+++ /dev/null
@@ -1,1004 +0,0 @@
-From b780c9e06cabe6d8e301aaf46f33f116f3224021 Mon Sep 17 00:00:00 2001
-From: Han Shen <shenhan@google.com>
-Date: Thu, 29 Jan 2015 10:00:46 -0800
-Subject: [PATCH] This patch adds IFUNC support for arm gold backend.
-
-This is a feature required in chromeos arm development work.
-
-Tested:
-1) Built passed all-gold on x86_64 machine
-2) Tested with basic gold aarch64 ifunc unittests -
- a) global ifunc, statically/non-statically linked
- b) local ifunc, statically/non-statically linked
- c) global/local, other shared library routine mixed,
- statically/non-statically linked
- d) arm/thumb mode ifunc
- e) linking chrome browser passed
----
-Upstream-Status: Backport
-Signed-off-by: Khem Raj <raj.khem@gmail.com>
-
- elfcpp/arm.h | 5 +-
- gold/aarch64.cc | 2 +-
- gold/arm.cc | 593 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
- gold/output.h | 11 ++
- 4 files changed, 561 insertions(+), 50 deletions(-)
-
-diff --git a/elfcpp/arm.h b/elfcpp/arm.h
-index 8c6b6bf..1c13dc9 100644
---- a/elfcpp/arm.h
-+++ b/elfcpp/arm.h
-@@ -192,11 +192,12 @@ enum
- R_ARM_PRIVATE_14 = 126,
- R_ARM_PRIVATE_15 = 127,
- R_ARM_ME_TOO = 128, // Obsolete
-- R_ARM_THM_TLS_DESCSEQ16 = 129,// Static Thumb16
-+ R_ARM_THM_TLS_DESCSEQ16 = 129,// Static Thumb16
- R_ARM_THM_TLS_DESCSEQ32 = 130,// Static Thumb32
- // 131 - 139 Unallocated
- // 140 - 159 Dynamic Reserved for future allocation
-- // 160 - 255 Unallocated
-+ R_ARM_IRELATIVE = 160, // Dynamic
-+ // 161 - 255 Unallocated
- };
-
- // e_flags values used for ARM. We only support flags defined in AAELF.
-diff --git a/gold/aarch64.cc b/gold/aarch64.cc
-index afb9024..7fbbdbd 100644
---- a/gold/aarch64.cc
-+++ b/gold/aarch64.cc
-@@ -1226,7 +1226,7 @@ class Output_data_plt_aarch64 : public Output_section_data
- // The number of PLT entries.
- unsigned int count_;
-
-- // Number of PLT entries with R_X86_64_IRELATIVE relocs. These
-+ // Number of PLT entries with R_AARCH64_IRELATIVE relocs. These
- // follow the regular PLT entries.
- unsigned int irelative_count_;
-
-diff --git a/gold/arm.cc b/gold/arm.cc
-index 6c472bb..8719cc9 100644
---- a/gold/arm.cc
-+++ b/gold/arm.cc
-@@ -2119,8 +2119,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 +2258,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>*,
-@@ -2357,6 +2369,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 +2464,11 @@ class Target_arm : public Sized_target<32, big_endian>
- protected:
- // Make the PLT-generator object.
- Output_data_plt_arm<big_endian>*
-- 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<big_endian>* 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 +2549,14 @@ class Target_arm : public Sized_target<32, big_endian>
- do_define_standard_symbols(Symbol_table*, Layout*);
-
- virtual Output_data_plt_arm<big_endian>*
-- do_make_data_plt(Layout* layout, Output_data_space* got_plt)
-+ do_make_data_plt(Layout* layout,
-+ Arm_output_data_got<big_endian>* got,
-+ Output_data_space* got_plt,
-+ Output_data_space* got_irelative)
- {
-- return new Output_data_plt_arm_standard<big_endian>(layout, got_plt);
-+ gold_assert(got_plt != NULL && got_irelative != NULL);
-+ return new Output_data_plt_arm_standard<big_endian>(
-+ layout, got, got_plt, got_irelative);
- }
-
- private:
-@@ -2602,6 +2626,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 +2640,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_;
- };
-@@ -2718,10 +2750,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*);
-@@ -2903,8 +2945,12 @@ class Target_arm : public Sized_target<32, big_endian>
- Output_data_plt_arm<big_endian>* 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<elfcpp::SHT_REL, 32, big_endian> copy_relocs_;
- // Offset of the GOT entry for the TLS module index.
-@@ -4244,6 +4290,15 @@ Target_arm<big_endian>::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 +4312,43 @@ Target_arm<big_endian>::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<bool big_endian>
-+typename Target_arm<big_endian>::Reloc_section*
-+Target_arm<big_endian>::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.
-@@ -7221,24 +7305,80 @@ template<bool big_endian>
- 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<elfcpp::SHT_REL, true, 32, big_endian>
- 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<big_endian>* 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 +7390,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 +7446,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<big_endian>* 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> IRelative_data_vec;
-+ IRelative_data_vec irelative_data_vec_;
- };
-
- // Create the PLT section. The ordinary .got section is an argument,
-@@ -7318,10 +7484,14 @@ class Output_data_plt_arm : public Output_section_data
- // section just for PLT entries.
-
- template<bool big_endian>
--Output_data_plt_arm<big_endian>::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<big_endian>::Output_data_plt_arm(
-+ Layout* layout, uint64_t addralign,
-+ Arm_output_data_got<big_endian>* 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 +7510,210 @@ Output_data_plt_arm<big_endian>::do_adjust_output_section(Output_section* os)
-
- template<bool big_endian>
- void
--Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym)
-+Output_data_plt_arm<big_endian>::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.
-+
-+ // IFunc plt entries *always* come after *normal* plt entries.
-+
-+ // 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());
-
-- ++this->count_;
-+ ++(*entry_count);
-
-- section_offset_type got_offset = this->got_plt_->current_data_size();
-+ 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<bool big_endian>
-+unsigned int
-+Output_data_plt_arm<big_endian>::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<bool big_endian>
-+void
-+Output_data_plt_arm<big_endian>::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<bool big_endian>
-+typename Output_data_plt_arm<big_endian>::Reloc_section*
-+Output_data_plt_arm<big_endian>::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<big_endian>* arm_target =
-+ Target_arm<big_endian>::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<bool big_endian>
-+uint32_t
-+Output_data_plt_arm<big_endian>::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<bool big_endian>
-+uint32_t
-+Output_data_plt_arm<big_endian>::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<bool big_endian>
- class Output_data_plt_arm_standard : public Output_data_plt_arm<big_endian>
- {
- public:
-- Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt)
-- : Output_data_plt_arm<big_endian>(layout, 4, got_plt)
-+ Output_data_plt_arm_standard(Layout* layout,
-+ Arm_output_data_got<big_endian>* got,
-+ Output_data_space* got_plt,
-+ Output_data_space* got_irelative)
-+ : Output_data_plt_arm<big_endian>(layout, 4, got, got_plt, got_irelative)
- { }
-
- protected:
-@@ -7485,8 +7825,11 @@ Output_data_plt_arm<big_endian>::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 +7848,8 @@ Output_data_plt_arm<big_endian>::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 +7862,33 @@ Output_data_plt_arm<big_endian>::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<section_size_type>(pov - oview) == oview_size);
-@@ -7529,6 +7898,7 @@ Output_data_plt_arm<big_endian>::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<bool big_endian>
-@@ -7540,20 +7910,58 @@ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout,
- return;
-
- if (this->plt_ == NULL)
-+ this->make_plt_section(symtab, layout);
-+
-+ this->plt_->add_entry(symtab, layout, gsym);
-+}
-+
-+
-+// Create the PLT section.
-+template<bool big_endian>
-+void
-+Target_arm<big_endian>::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);
- }
-- this->plt_->add_entry(gsym);
- }
-
-+
-+// Make a PLT entry for a local STT_GNU_IFUNC symbol.
-+
-+template<bool big_endian>
-+void
-+Target_arm<big_endian>::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<bool big_endian>
-@@ -7823,6 +8231,7 @@ Target_arm<big_endian>::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 +8262,27 @@ Target_arm<big_endian>::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 big_endian>
-+bool
-+Target_arm<big_endian>::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 +8304,15 @@ Target_arm<big_endian>::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 +8337,7 @@ Target_arm<big_endian>::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 +8704,11 @@ Target_arm<big_endian>::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)
- {
-@@ -8309,6 +8753,24 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
- }
- 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))
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
-@@ -8442,7 +8904,13 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
- Arm_output_data_got<big_endian>* 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 +8920,29 @@ Target_arm<big_endian>::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));
-@@ -8919,8 +9404,7 @@ Target_arm<big_endian>::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 +9442,13 @@ Target_arm<big_endian>::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
-@@ -9936,7 +10427,7 @@ uint64_t
- Target_arm<big_endian>::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
-@@ -11083,8 +11574,7 @@ Target_arm<big_endian>::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;
- }
-@@ -12187,8 +12677,13 @@ class Target_arm_nacl : public Target_arm<big_endian>
-
- protected:
- virtual Output_data_plt_arm<big_endian>*
-- do_make_data_plt(Layout* layout, Output_data_space* got_plt)
-- { return new Output_data_plt_arm_nacl<big_endian>(layout, got_plt); }
-+ do_make_data_plt(
-+ Layout* layout,
-+ Arm_output_data_got<big_endian>* got,
-+ Output_data_space* got_plt,
-+ Output_data_space* got_irelative)
-+ { return new Output_data_plt_arm_nacl<big_endian>(
-+ layout, got, got_plt, got_irelative); }
-
- private:
- static const Target::Target_info arm_nacl_info;
-@@ -12225,8 +12720,12 @@ template<bool big_endian>
- class Output_data_plt_arm_nacl : public Output_data_plt_arm<big_endian>
- {
- public:
-- Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt)
-- : Output_data_plt_arm<big_endian>(layout, 16, got_plt)
-+ Output_data_plt_arm_nacl(
-+ Layout* layout,
-+ Arm_output_data_got<big_endian>* got,
-+ Output_data_space* got_plt,
-+ Output_data_space* got_irelative)
-+ : Output_data_plt_arm<big_endian>(layout, 16, got, got_plt, got_irelative)
- { }
-
- protected:
-diff --git a/gold/output.h b/gold/output.h
-index ba0cdaa..599c2b7 100644
---- a/gold/output.h
-+++ b/gold/output.h
-@@ -1714,6 +1714,17 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
- address, true, true, false, false));
- }
-
-+ void
-+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
-+ unsigned int local_sym_index, unsigned int type,
-+ Output_data* od, unsigned int shndx, Address address,
-+ bool use_plt_offset)
-+ {
-+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-+ address, true, true, false,
-+ use_plt_offset));
-+ }
-+
- // Add a local relocation which does not use a symbol for the relocation,
- // but which gets its addend from a symbol.
-
---
-2.7.0
-