summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/binutils
diff options
context:
space:
mode:
authorKhem Raj <raj.khem@gmail.com>2016-01-14 03:58:10 -0800
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-01-24 09:40:31 +0000
commit136db70700ce198f793935d0683ce4e1f1acf471 (patch)
tree4d197ae3c35c91a8dee182f21158873abd6e1fa5 /meta/recipes-devtools/binutils
parent704e34213ed2925ab3ac135717861c4ff466e8ab (diff)
downloadpoky-136db70700ce198f793935d0683ce4e1f1acf471.tar.gz
binutils: Fix gold linking errors due to unresolved R_ARM_MOVW_ABS_NC
This issue has been seen in multiple times e.g. http://patchwork.openembedded.org/patch/103083/ https://www.mail-archive.com/openembedded-core@lists.openembedded.org/msg72513.html (From OE-Core rev: 9db094039ed7bce34006cc21bb65cd800fbfee7d) Signed-off-by: Khem Raj <raj.khem@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-devtools/binutils')
-rw-r--r--meta/recipes-devtools/binutils/binutils-2.25.1.inc1
-rw-r--r--meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch1004
2 files changed, 1005 insertions, 0 deletions
diff --git a/meta/recipes-devtools/binutils/binutils-2.25.1.inc b/meta/recipes-devtools/binutils/binutils-2.25.1.inc
index bf29da16f5..dc23c4d9d9 100644
--- a/meta/recipes-devtools/binutils/binutils-2.25.1.inc
+++ b/meta/recipes-devtools/binutils/binutils-2.25.1.inc
@@ -35,6 +35,7 @@ SRC_URI = "\
35 file://0013-Fix-an-internal-error-in-do_print_to_mapfile-seen-wi.patch \ 35 file://0013-Fix-an-internal-error-in-do_print_to_mapfile-seen-wi.patch \
36 file://0014-gold-arm-Skip-pic-check-for-R_ARM_REL32.patch \ 36 file://0014-gold-arm-Skip-pic-check-for-R_ARM_REL32.patch \
37 file://0015-Fix-dynamic-list-so-that-symbols-not-in-the-list-are.patch \ 37 file://0015-Fix-dynamic-list-so-that-symbols-not-in-the-list-are.patch \
38 file://0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch \
38 file://binutils-octeon3.patch \ 39 file://binutils-octeon3.patch \
39 file://add-thunderx-support-for-gas.patch \ 40 file://add-thunderx-support-for-gas.patch \
40 " 41 "
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
new file mode 100644
index 0000000000..dcac308bcc
--- /dev/null
+++ b/meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch
@@ -0,0 +1,1004 @@
1From b780c9e06cabe6d8e301aaf46f33f116f3224021 Mon Sep 17 00:00:00 2001
2From: Han Shen <shenhan@google.com>
3Date: Thu, 29 Jan 2015 10:00:46 -0800
4Subject: [PATCH] This patch adds IFUNC support for arm gold backend.
5
6This is a feature required in chromeos arm development work.
7
8Tested:
91) Built passed all-gold on x86_64 machine
102) Tested with basic gold aarch64 ifunc unittests -
11 a) global ifunc, statically/non-statically linked
12 b) local ifunc, statically/non-statically linked
13 c) global/local, other shared library routine mixed,
14 statically/non-statically linked
15 d) arm/thumb mode ifunc
16 e) linking chrome browser passed
17---
18Upstream-Status: Backport
19Signed-off-by: Khem Raj <raj.khem@gmail.com>
20
21 elfcpp/arm.h | 5 +-
22 gold/aarch64.cc | 2 +-
23 gold/arm.cc | 593 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
24 gold/output.h | 11 ++
25 4 files changed, 561 insertions(+), 50 deletions(-)
26
27diff --git a/elfcpp/arm.h b/elfcpp/arm.h
28index 8c6b6bf..1c13dc9 100644
29--- a/elfcpp/arm.h
30+++ b/elfcpp/arm.h
31@@ -192,11 +192,12 @@ enum
32 R_ARM_PRIVATE_14 = 126,
33 R_ARM_PRIVATE_15 = 127,
34 R_ARM_ME_TOO = 128, // Obsolete
35- R_ARM_THM_TLS_DESCSEQ16 = 129,// Static Thumb16
36+ R_ARM_THM_TLS_DESCSEQ16 = 129,// Static Thumb16
37 R_ARM_THM_TLS_DESCSEQ32 = 130,// Static Thumb32
38 // 131 - 139 Unallocated
39 // 140 - 159 Dynamic Reserved for future allocation
40- // 160 - 255 Unallocated
41+ R_ARM_IRELATIVE = 160, // Dynamic
42+ // 161 - 255 Unallocated
43 };
44
45 // e_flags values used for ARM. We only support flags defined in AAELF.
46diff --git a/gold/aarch64.cc b/gold/aarch64.cc
47index afb9024..7fbbdbd 100644
48--- a/gold/aarch64.cc
49+++ b/gold/aarch64.cc
50@@ -1226,7 +1226,7 @@ class Output_data_plt_aarch64 : public Output_section_data
51 // The number of PLT entries.
52 unsigned int count_;
53
54- // Number of PLT entries with R_X86_64_IRELATIVE relocs. These
55+ // Number of PLT entries with R_AARCH64_IRELATIVE relocs. These
56 // follow the regular PLT entries.
57 unsigned int irelative_count_;
58
59diff --git a/gold/arm.cc b/gold/arm.cc
60index 6c472bb..8719cc9 100644
61--- a/gold/arm.cc
62+++ b/gold/arm.cc
63@@ -2119,8 +2119,8 @@ class Target_arm : public Sized_target<32, big_endian>
64
65 Target_arm(const Target::Target_info* info = &arm_info)
66 : Sized_target<32, big_endian>(info),
67- got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
68- copy_relocs_(elfcpp::R_ARM_COPY),
69+ got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
70+ rel_dyn_(NULL), rel_irelative_(NULL), copy_relocs_(elfcpp::R_ARM_COPY),
71 got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
72 stub_tables_(), stub_factory_(Stub_factory::get_instance()),
73 should_force_pic_veneer_(false),
74@@ -2258,6 +2258,18 @@ class Target_arm : public Sized_target<32, big_endian>
75 uint64_t
76 do_dynsym_value(const Symbol*) const;
77
78+ // Return the plt address for globals. Since we have irelative plt entries,
79+ // address calculation is not as straightforward as plt_address + plt_offset.
80+ uint64_t
81+ do_plt_address_for_global(const Symbol* gsym) const
82+ { return this->plt_section()->address_for_global(gsym); }
83+
84+ // Return the plt address for locals. Since we have irelative plt entries,
85+ // address calculation is not as straightforward as plt_address + plt_offset.
86+ uint64_t
87+ do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const
88+ { return this->plt_section()->address_for_local(relobj, symndx); }
89+
90 // Relocate a section.
91 void
92 relocate_section(const Relocate_info<32, big_endian>*,
93@@ -2357,6 +2369,10 @@ class Target_arm : public Sized_target<32, big_endian>
94 unsigned int
95 plt_entry_size() const;
96
97+ // Get the section to use for IRELATIVE relocations, create it if necessary.
98+ Reloc_section*
99+ rel_irelative_section(Layout*);
100+
101 // Map platform-specific reloc types
102 static unsigned int
103 get_real_reloc_type(unsigned int r_type);
104@@ -2448,8 +2464,11 @@ class Target_arm : public Sized_target<32, big_endian>
105 protected:
106 // Make the PLT-generator object.
107 Output_data_plt_arm<big_endian>*
108- make_data_plt(Layout* layout, Output_data_space* got_plt)
109- { return this->do_make_data_plt(layout, got_plt); }
110+ make_data_plt(Layout* layout,
111+ Arm_output_data_got<big_endian>* got,
112+ Output_data_space* got_plt,
113+ Output_data_space* got_irelative)
114+ { return this->do_make_data_plt(layout, got, got_plt, got_irelative); }
115
116 // Make an ELF object.
117 Object*
118@@ -2530,9 +2549,14 @@ class Target_arm : public Sized_target<32, big_endian>
119 do_define_standard_symbols(Symbol_table*, Layout*);
120
121 virtual Output_data_plt_arm<big_endian>*
122- do_make_data_plt(Layout* layout, Output_data_space* got_plt)
123+ do_make_data_plt(Layout* layout,
124+ Arm_output_data_got<big_endian>* got,
125+ Output_data_space* got_plt,
126+ Output_data_space* got_irelative)
127 {
128- return new Output_data_plt_arm_standard<big_endian>(layout, got_plt);
129+ gold_assert(got_plt != NULL && got_irelative != NULL);
130+ return new Output_data_plt_arm_standard<big_endian>(
131+ layout, got, got_plt, got_irelative);
132 }
133
134 private:
135@@ -2602,6 +2626,9 @@ class Target_arm : public Sized_target<32, big_endian>
136 if (sym->is_undefined() && !parameters->options().shared())
137 return false;
138
139+ if (sym->type() == elfcpp::STT_GNU_IFUNC)
140+ return true;
141+
142 return (!parameters->doing_static_link()
143 && (sym->type() == elfcpp::STT_FUNC
144 || sym->type() == elfcpp::STT_ARM_TFUNC)
145@@ -2613,6 +2640,11 @@ class Target_arm : public Sized_target<32, big_endian>
146 inline bool
147 possible_function_pointer_reloc(unsigned int r_type);
148
149+ // Whether a plt entry is needed for ifunc.
150+ bool
151+ reloc_needs_plt_for_ifunc(Sized_relobj_file<32, big_endian>*,
152+ unsigned int r_type);
153+
154 // Whether we have issued an error about a non-PIC compilation.
155 bool issued_non_pic_error_;
156 };
157@@ -2718,10 +2750,20 @@ class Target_arm : public Sized_target<32, big_endian>
158 return this->got_plt_;
159 }
160
161+ // Create the PLT section.
162+ void
163+ make_plt_section(Symbol_table* symtab, Layout* layout);
164+
165 // Create a PLT entry for a global symbol.
166 void
167 make_plt_entry(Symbol_table*, Layout*, Symbol*);
168
169+ // Create a PLT entry for a local STT_GNU_IFUNC symbol.
170+ void
171+ make_local_ifunc_plt_entry(Symbol_table*, Layout*,
172+ Sized_relobj_file<32, big_endian>* relobj,
173+ unsigned int local_sym_index);
174+
175 // Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
176 void
177 define_tls_base_symbol(Symbol_table*, Layout*);
178@@ -2903,8 +2945,12 @@ class Target_arm : public Sized_target<32, big_endian>
179 Output_data_plt_arm<big_endian>* plt_;
180 // The GOT PLT section.
181 Output_data_space* got_plt_;
182+ // The GOT section for IRELATIVE relocations.
183+ Output_data_space* got_irelative_;
184 // The dynamic reloc section.
185 Reloc_section* rel_dyn_;
186+ // The section to use for IRELATIVE relocs.
187+ Reloc_section* rel_irelative_;
188 // Relocs saved to avoid a COPY reloc.
189 Copy_relocs<elfcpp::SHT_REL, 32, big_endian> copy_relocs_;
190 // Offset of the GOT entry for the TLS module index.
191@@ -4244,6 +4290,15 @@ Target_arm<big_endian>::got_section(Symbol_table* symtab, Layout* layout)
192 elfcpp::STB_LOCAL,
193 elfcpp::STV_HIDDEN, 0,
194 false, false);
195+
196+ // If there are any IRELATIVE relocations, they get GOT entries
197+ // in .got.plt after the jump slot entries.
198+ this->got_irelative_ = new Output_data_space(4, "** GOT IRELATIVE PLT");
199+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
200+ (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
201+ this->got_irelative_,
202+ got_order, is_got_relro);
203+
204 }
205 return this->got_;
206 }
207@@ -4257,14 +4312,43 @@ Target_arm<big_endian>::rel_dyn_section(Layout* layout)
208 if (this->rel_dyn_ == NULL)
209 {
210 gold_assert(layout != NULL);
211+ // Create both relocation sections in the same place, so as to ensure
212+ // their relative order in the output section.
213 this->rel_dyn_ = new Reloc_section(parameters->options().combreloc());
214+ this->rel_irelative_ = new Reloc_section(false);
215 layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
216 elfcpp::SHF_ALLOC, this->rel_dyn_,
217 ORDER_DYNAMIC_RELOCS, false);
218+ layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
219+ elfcpp::SHF_ALLOC, this->rel_irelative_,
220+ ORDER_DYNAMIC_RELOCS, false);
221 }
222 return this->rel_dyn_;
223 }
224
225+
226+// Get the section to use for IRELATIVE relocs, creating it if necessary. These
227+// go in .rela.dyn, but only after all other dynamic relocations. They need to
228+// follow the other dynamic relocations so that they can refer to global
229+// variables initialized by those relocs.
230+
231+template<bool big_endian>
232+typename Target_arm<big_endian>::Reloc_section*
233+Target_arm<big_endian>::rel_irelative_section(Layout* layout)
234+{
235+ if (this->rel_irelative_ == NULL)
236+ {
237+ // Delegate the creation to rel_dyn_section so as to ensure their order in
238+ // the output section.
239+ this->rel_dyn_section(layout);
240+ gold_assert(this->rel_irelative_ != NULL
241+ && (this->rel_dyn_->output_section()
242+ == this->rel_irelative_->output_section()));
243+ }
244+ return this->rel_irelative_;
245+}
246+
247+
248 // Insn_template methods.
249
250 // Return byte size of an instruction template.
251@@ -7221,24 +7305,80 @@ template<bool big_endian>
252 class Output_data_plt_arm : public Output_section_data
253 {
254 public:
255+ // Unlike aarch64, which records symbol value in "addend" field of relocations
256+ // and could be done at the same time an IRelative reloc is created for the
257+ // symbol, arm puts the symbol value into "GOT" table, which, however, is
258+ // issued later in Output_data_plt_arm::do_write(). So we have a struct here
259+ // to keep necessary symbol information for later use in do_write. We usually
260+ // have only a very limited number of ifuncs, so the extra data required here
261+ // is also limited.
262+
263+ struct IRelative_data
264+ {
265+ IRelative_data(Sized_symbol<32>* sized_symbol)
266+ : symbol_is_global_(true)
267+ {
268+ u_.global = sized_symbol;
269+ }
270+
271+ IRelative_data(Sized_relobj_file<32, big_endian>* relobj,
272+ unsigned int index)
273+ : symbol_is_global_(false)
274+ {
275+ u_.local.relobj = relobj;
276+ u_.local.index = index;
277+ }
278+
279+ union
280+ {
281+ Sized_symbol<32>* global;
282+
283+ struct
284+ {
285+ Sized_relobj_file<32, big_endian>* relobj;
286+ unsigned int index;
287+ } local;
288+ } u_;
289+
290+ bool symbol_is_global_;
291+ };
292+
293 typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
294 Reloc_section;
295
296- Output_data_plt_arm(Layout*, uint64_t addralign, Output_data_space*);
297+ Output_data_plt_arm(Layout* layout, uint64_t addralign,
298+ Arm_output_data_got<big_endian>* got,
299+ Output_data_space* got_plt,
300+ Output_data_space* got_irelative);
301
302 // Add an entry to the PLT.
303 void
304- add_entry(Symbol* gsym);
305+ add_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym);
306+
307+ // Add the relocation for a plt entry.
308+ void
309+ add_relocation(Symbol_table* symtab, Layout* layout,
310+ Symbol* gsym, unsigned int got_offset);
311+
312+ // Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
313+ unsigned int
314+ add_local_ifunc_entry(Symbol_table* symtab, Layout*,
315+ Sized_relobj_file<32, big_endian>* relobj,
316+ unsigned int local_sym_index);
317
318 // Return the .rel.plt section data.
319 const Reloc_section*
320 rel_plt() const
321 { return this->rel_; }
322
323+ // Return the PLT relocation container for IRELATIVE.
324+ Reloc_section*
325+ rel_irelative(Symbol_table*, Layout*);
326+
327 // Return the number of PLT entries.
328 unsigned int
329 entry_count() const
330- { return this->count_; }
331+ { return this->count_ + this->irelative_count_; }
332
333 // Return the offset of the first non-reserved PLT entry.
334 unsigned int
335@@ -7250,6 +7390,14 @@ class Output_data_plt_arm : public Output_section_data
336 get_plt_entry_size() const
337 { return this->do_get_plt_entry_size(); }
338
339+ // Return the PLT address for globals.
340+ uint32_t
341+ address_for_global(const Symbol*) const;
342+
343+ // Return the PLT address for locals.
344+ uint32_t
345+ address_for_local(const Relobj*, unsigned int symndx) const;
346+
347 protected:
348 // Fill in the first PLT entry.
349 void
350@@ -7298,19 +7446,37 @@ class Output_data_plt_arm : public Output_section_data
351 set_final_data_size()
352 {
353 this->set_data_size(this->first_plt_entry_offset()
354- + this->count_ * this->get_plt_entry_size());
355+ + ((this->count_ + this->irelative_count_)
356+ * this->get_plt_entry_size()));
357 }
358
359 // Write out the PLT data.
360 void
361 do_write(Output_file*);
362
363+ // Record irelative symbol data.
364+ void insert_irelative_data(const IRelative_data& idata)
365+ { irelative_data_vec_.push_back(idata); }
366+
367 // The reloc section.
368 Reloc_section* rel_;
369+ // The IRELATIVE relocs, if necessary. These must follow the
370+ // regular PLT relocations.
371+ Reloc_section* irelative_rel_;
372+ // The .got section.
373+ Arm_output_data_got<big_endian>* got_;
374 // The .got.plt section.
375 Output_data_space* got_plt_;
376+ // The part of the .got.plt section used for IRELATIVE relocs.
377+ Output_data_space* got_irelative_;
378 // The number of PLT entries.
379 unsigned int count_;
380+ // Number of PLT entries with R_ARM_IRELATIVE relocs. These
381+ // follow the regular PLT entries.
382+ unsigned int irelative_count_;
383+ // Vector for irelative data.
384+ typedef std::vector<IRelative_data> IRelative_data_vec;
385+ IRelative_data_vec irelative_data_vec_;
386 };
387
388 // Create the PLT section. The ordinary .got section is an argument,
389@@ -7318,10 +7484,14 @@ class Output_data_plt_arm : public Output_section_data
390 // section just for PLT entries.
391
392 template<bool big_endian>
393-Output_data_plt_arm<big_endian>::Output_data_plt_arm(Layout* layout,
394- uint64_t addralign,
395- Output_data_space* got_plt)
396- : Output_section_data(addralign), got_plt_(got_plt), count_(0)
397+Output_data_plt_arm<big_endian>::Output_data_plt_arm(
398+ Layout* layout, uint64_t addralign,
399+ Arm_output_data_got<big_endian>* got,
400+ Output_data_space* got_plt,
401+ Output_data_space* got_irelative)
402+ : Output_section_data(addralign), irelative_rel_(NULL),
403+ got_(got), got_plt_(got_plt), got_irelative_(got_irelative),
404+ count_(0), irelative_count_(0)
405 {
406 this->rel_ = new Reloc_section(false);
407 layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
408@@ -7340,40 +7510,210 @@ Output_data_plt_arm<big_endian>::do_adjust_output_section(Output_section* os)
409
410 template<bool big_endian>
411 void
412-Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym)
413+Output_data_plt_arm<big_endian>::add_entry(Symbol_table* symtab,
414+ Layout* layout,
415+ Symbol* gsym)
416 {
417 gold_assert(!gsym->has_plt_offset());
418
419- // Note that when setting the PLT offset we skip the initial
420- // reserved PLT entry.
421- gsym->set_plt_offset((this->count_) * this->get_plt_entry_size()
422- + this->first_plt_entry_offset());
423+ unsigned int* entry_count;
424+ Output_section_data_build* got;
425+
426+ // We have 2 different types of plt entry here, normal and ifunc.
427+
428+ // For normal plt, the offset begins with first_plt_entry_offset(20), and the
429+ // 1st entry offset would be 20, the second 32, third 44 ... etc.
430+
431+ // For ifunc plt, the offset begins with 0. So the first offset would 0,
432+ // second 12, third 24 ... etc.
433+
434+ // IFunc plt entries *always* come after *normal* plt entries.
435+
436+ // Notice, when computing the plt address of a certain symbol, "plt_address +
437+ // plt_offset" is no longer correct. Use target->plt_address_for_global() or
438+ // target->plt_address_for_local() instead.
439+
440+ int begin_offset = 0;
441+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
442+ && gsym->can_use_relative_reloc(false))
443+ {
444+ entry_count = &this->irelative_count_;
445+ got = this->got_irelative_;
446+ // For irelative plt entries, offset is relative to the end of normal plt
447+ // entries, so it starts from 0.
448+ begin_offset = 0;
449+ // Record symbol information.
450+ this->insert_irelative_data(
451+ IRelative_data(symtab->get_sized_symbol<32>(gsym)));
452+ }
453+ else
454+ {
455+ entry_count = &this->count_;
456+ got = this->got_plt_;
457+ // Note that for normal plt entries, when setting the PLT offset we skip
458+ // the initial reserved PLT entry.
459+ begin_offset = this->first_plt_entry_offset();
460+ }
461+
462+ gsym->set_plt_offset(begin_offset
463+ + (*entry_count) * this->get_plt_entry_size());
464
465- ++this->count_;
466+ ++(*entry_count);
467
468- section_offset_type got_offset = this->got_plt_->current_data_size();
469+ section_offset_type got_offset = got->current_data_size();
470
471 // Every PLT entry needs a GOT entry which points back to the PLT
472 // entry (this will be changed by the dynamic linker, normally
473 // lazily when the function is called).
474- this->got_plt_->set_current_data_size(got_offset + 4);
475+ got->set_current_data_size(got_offset + 4);
476
477 // Every PLT entry needs a reloc.
478- gsym->set_needs_dynsym_entry();
479- this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_,
480- got_offset);
481+ this->add_relocation(symtab, layout, gsym, got_offset);
482
483 // Note that we don't need to save the symbol. The contents of the
484 // PLT are independent of which symbols are used. The symbols only
485 // appear in the relocations.
486 }
487
488+// Add an entry to the PLT for a local STT_GNU_IFUNC symbol. Return
489+// the PLT offset.
490+
491+template<bool big_endian>
492+unsigned int
493+Output_data_plt_arm<big_endian>::add_local_ifunc_entry(
494+ Symbol_table* symtab,
495+ Layout* layout,
496+ Sized_relobj_file<32, big_endian>* relobj,
497+ unsigned int local_sym_index)
498+{
499+ this->insert_irelative_data(IRelative_data(relobj, local_sym_index));
500+
501+ // Notice, when computingthe plt entry address, "plt_address + plt_offset" is
502+ // no longer correct. Use target->plt_address_for_local() instead.
503+ unsigned int plt_offset = this->irelative_count_ * this->get_plt_entry_size();
504+ ++this->irelative_count_;
505+
506+ section_offset_type got_offset = this->got_irelative_->current_data_size();
507+
508+ // Every PLT entry needs a GOT entry which points back to the PLT
509+ // entry.
510+ this->got_irelative_->set_current_data_size(got_offset + 4);
511+
512+
513+ // Every PLT entry needs a reloc.
514+ Reloc_section* rel = this->rel_irelative(symtab, layout);
515+ rel->add_symbolless_local_addend(relobj, local_sym_index,
516+ elfcpp::R_ARM_IRELATIVE,
517+ this->got_irelative_, got_offset);
518+ return plt_offset;
519+}
520+
521+
522+// Add the relocation for a PLT entry.
523+
524+template<bool big_endian>
525+void
526+Output_data_plt_arm<big_endian>::add_relocation(
527+ Symbol_table* symtab, Layout* layout, Symbol* gsym, unsigned int got_offset)
528+{
529+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
530+ && gsym->can_use_relative_reloc(false))
531+ {
532+ Reloc_section* rel = this->rel_irelative(symtab, layout);
533+ rel->add_symbolless_global_addend(gsym, elfcpp::R_ARM_IRELATIVE,
534+ this->got_irelative_, got_offset);
535+ }
536+ else
537+ {
538+ gsym->set_needs_dynsym_entry();
539+ this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_,
540+ got_offset);
541+ }
542+}
543+
544+
545+// Create the irelative relocation data.
546+
547+template<bool big_endian>
548+typename Output_data_plt_arm<big_endian>::Reloc_section*
549+Output_data_plt_arm<big_endian>::rel_irelative(Symbol_table* symtab,
550+ Layout* layout)
551+{
552+ if (this->irelative_rel_ == NULL)
553+ {
554+ // Since irelative relocations goes into 'rel.dyn', we delegate the
555+ // creation of irelative_rel_ to where rel_dyn section gets created.
556+ Target_arm<big_endian>* arm_target =
557+ Target_arm<big_endian>::default_target();
558+ this->irelative_rel_ = arm_target->rel_irelative_section(layout);
559+
560+ // Make sure we have a place for the TLSDESC relocations, in
561+ // case we see any later on.
562+ // this->rel_tlsdesc(layout);
563+ if (parameters->doing_static_link())
564+ {
565+ // A statically linked executable will only have a .rel.plt section to
566+ // hold R_ARM_IRELATIVE relocs for STT_GNU_IFUNC symbols. The library
567+ // will use these symbols to locate the IRELATIVE relocs at program
568+ // startup time.
569+ symtab->define_in_output_data("__rel_iplt_start", NULL,
570+ Symbol_table::PREDEFINED,
571+ this->irelative_rel_, 0, 0,
572+ elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
573+ elfcpp::STV_HIDDEN, 0, false, true);
574+ symtab->define_in_output_data("__rel_iplt_end", NULL,
575+ Symbol_table::PREDEFINED,
576+ this->irelative_rel_, 0, 0,
577+ elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
578+ elfcpp::STV_HIDDEN, 0, true, true);
579+ }
580+ }
581+ return this->irelative_rel_;
582+}
583+
584+
585+// Return the PLT address for a global symbol.
586+
587+template<bool big_endian>
588+uint32_t
589+Output_data_plt_arm<big_endian>::address_for_global(const Symbol* gsym) const
590+{
591+ uint64_t begin_offset = 0;
592+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
593+ && gsym->can_use_relative_reloc(false))
594+ {
595+ begin_offset = (this->first_plt_entry_offset() +
596+ this->count_ * this->get_plt_entry_size());
597+ }
598+ return this->address() + begin_offset + gsym->plt_offset();
599+}
600+
601+
602+// Return the PLT address for a local symbol. These are always
603+// IRELATIVE relocs.
604+
605+template<bool big_endian>
606+uint32_t
607+Output_data_plt_arm<big_endian>::address_for_local(
608+ const Relobj* object,
609+ unsigned int r_sym) const
610+{
611+ return (this->address()
612+ + this->first_plt_entry_offset()
613+ + this->count_ * this->get_plt_entry_size()
614+ + object->local_plt_offset(r_sym));
615+}
616+
617+
618 template<bool big_endian>
619 class Output_data_plt_arm_standard : public Output_data_plt_arm<big_endian>
620 {
621 public:
622- Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt)
623- : Output_data_plt_arm<big_endian>(layout, 4, got_plt)
624+ Output_data_plt_arm_standard(Layout* layout,
625+ Arm_output_data_got<big_endian>* got,
626+ Output_data_space* got_plt,
627+ Output_data_space* got_irelative)
628+ : Output_data_plt_arm<big_endian>(layout, 4, got, got_plt, got_irelative)
629 { }
630
631 protected:
632@@ -7485,8 +7825,11 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of)
633 unsigned char* const oview = of->get_output_view(offset, oview_size);
634
635 const off_t got_file_offset = this->got_plt_->offset();
636+ gold_assert(got_file_offset + this->got_plt_->data_size()
637+ == this->got_irelative_->offset());
638 const section_size_type got_size =
639- convert_to_section_size_type(this->got_plt_->data_size());
640+ convert_to_section_size_type(this->got_plt_->data_size()
641+ + this->got_irelative_->data_size());
642 unsigned char* const got_view = of->get_output_view(got_file_offset,
643 got_size);
644 unsigned char* pov = oview;
645@@ -7505,7 +7848,8 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of)
646
647 unsigned int plt_offset = this->first_plt_entry_offset();
648 unsigned int got_offset = 12;
649- const unsigned int count = this->count_;
650+ const unsigned int count = this->count_ + this->irelative_count_;
651+ gold_assert(this->irelative_count_ == this->irelative_data_vec_.size());
652 for (unsigned int i = 0;
653 i < count;
654 ++i,
655@@ -7518,8 +7862,33 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of)
656 this->fill_plt_entry(pov, got_address, plt_address,
657 got_offset, plt_offset);
658
659- // Set the entry in the GOT.
660- elfcpp::Swap<32, big_endian>::writeval(got_pov, plt_address);
661+ Arm_address value;
662+ if (i < this->count_)
663+ {
664+ // For non-irelative got entries, the value is the beginning of plt.
665+ value = plt_address;
666+ }
667+ else
668+ {
669+ // For irelative got entries, the value is the (global/local) symbol
670+ // address.
671+ const IRelative_data& idata =
672+ this->irelative_data_vec_[i - this->count_];
673+ if (idata.symbol_is_global_)
674+ {
675+ // Set the entry in the GOT for irelative symbols. The content is
676+ // the address of the ifunc, not the address of plt start.
677+ const Sized_symbol<32>* sized_symbol = idata.u_.global;
678+ gold_assert(sized_symbol->type() == elfcpp::STT_GNU_IFUNC);
679+ value = sized_symbol->value();
680+ }
681+ else
682+ {
683+ value = idata.u_.local.relobj->local_symbol_value(
684+ idata.u_.local.index, 0);
685+ }
686+ }
687+ elfcpp::Swap<32, big_endian>::writeval(got_pov, value);
688 }
689
690 gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
691@@ -7529,6 +7898,7 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of)
692 of->write_output_view(got_file_offset, got_size, got_view);
693 }
694
695+
696 // Create a PLT entry for a global symbol.
697
698 template<bool big_endian>
699@@ -7540,20 +7910,58 @@ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout,
700 return;
701
702 if (this->plt_ == NULL)
703+ this->make_plt_section(symtab, layout);
704+
705+ this->plt_->add_entry(symtab, layout, gsym);
706+}
707+
708+
709+// Create the PLT section.
710+template<bool big_endian>
711+void
712+Target_arm<big_endian>::make_plt_section(
713+ Symbol_table* symtab, Layout* layout)
714+{
715+ if (this->plt_ == NULL)
716 {
717- // Create the GOT sections first.
718+ // Create the GOT section first.
719 this->got_section(symtab, layout);
720
721- this->plt_ = this->make_data_plt(layout, this->got_plt_);
722+ // GOT for irelatives is create along with got.plt.
723+ gold_assert(this->got_ != NULL
724+ && this->got_plt_ != NULL
725+ && this->got_irelative_ != NULL);
726+ this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_,
727+ this->got_irelative_);
728
729 layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
730 (elfcpp::SHF_ALLOC
731 | elfcpp::SHF_EXECINSTR),
732 this->plt_, ORDER_PLT, false);
733 }
734- this->plt_->add_entry(gsym);
735 }
736
737+
738+// Make a PLT entry for a local STT_GNU_IFUNC symbol.
739+
740+template<bool big_endian>
741+void
742+Target_arm<big_endian>::make_local_ifunc_plt_entry(
743+ Symbol_table* symtab, Layout* layout,
744+ Sized_relobj_file<32, big_endian>* relobj,
745+ unsigned int local_sym_index)
746+{
747+ if (relobj->local_has_plt_offset(local_sym_index))
748+ return;
749+ if (this->plt_ == NULL)
750+ this->make_plt_section(symtab, layout);
751+ unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout,
752+ relobj,
753+ local_sym_index);
754+ relobj->set_local_plt_offset(local_sym_index, plt_offset);
755+}
756+
757+
758 // Return the number of entries in the PLT.
759
760 template<bool big_endian>
761@@ -7823,6 +8231,7 @@ Target_arm<big_endian>::Scan::check_non_pic(Relobj* object,
762 case elfcpp::R_ARM_JUMP_SLOT:
763 case elfcpp::R_ARM_ABS32:
764 case elfcpp::R_ARM_ABS32_NOI:
765+ case elfcpp::R_ARM_IRELATIVE:
766 case elfcpp::R_ARM_PC24:
767 // FIXME: The following 3 types are not supported by Android's dynamic
768 // linker.
769@@ -7853,6 +8262,27 @@ Target_arm<big_endian>::Scan::check_non_pic(Relobj* object,
770 }
771 }
772
773+
774+// Return whether we need to make a PLT entry for a relocation of the
775+// given type against a STT_GNU_IFUNC symbol.
776+
777+template<bool big_endian>
778+bool
779+Target_arm<big_endian>::Scan::reloc_needs_plt_for_ifunc(
780+ Sized_relobj_file<32, big_endian>* object,
781+ unsigned int r_type)
782+{
783+ int flags = Scan::get_reference_flags(r_type);
784+ if (flags & Symbol::TLS_REF)
785+ {
786+ gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
787+ object->name().c_str(), r_type);
788+ return false;
789+ }
790+ return flags != 0;
791+}
792+
793+
794 // Scan a relocation for a local symbol.
795 // FIXME: This only handles a subset of relocation types used by Android
796 // on ARM v5te devices.
797@@ -7874,6 +8304,15 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
798 return;
799
800 r_type = get_real_reloc_type(r_type);
801+
802+ // A local STT_GNU_IFUNC symbol may require a PLT entry.
803+ bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
804+ if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
805+ {
806+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
807+ target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
808+ }
809+
810 switch (r_type)
811 {
812 case elfcpp::R_ARM_NONE:
813@@ -7898,7 +8337,7 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
814 // we need to add check_non_pic(object, r_type) here.
815 rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE,
816 output_section, data_shndx,
817- reloc.get_r_offset());
818+ reloc.get_r_offset(), is_ifunc);
819 }
820 break;
821
822@@ -8265,6 +8704,11 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
823 && strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
824 target->got_section(symtab, layout);
825
826+ // A STT_GNU_IFUNC symbol may require a PLT entry.
827+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
828+ && this->reloc_needs_plt_for_ifunc(object, r_type))
829+ target->make_plt_entry(symtab, layout, gsym);
830+
831 r_type = get_real_reloc_type(r_type);
832 switch (r_type)
833 {
834@@ -8309,6 +8753,24 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
835 }
836 else if ((r_type == elfcpp::R_ARM_ABS32
837 || r_type == elfcpp::R_ARM_ABS32_NOI)
838+ && gsym->type() == elfcpp::STT_GNU_IFUNC
839+ && gsym->can_use_relative_reloc(false)
840+ && !gsym->is_from_dynobj()
841+ && !gsym->is_undefined()
842+ && !gsym->is_preemptible())
843+ {
844+ // Use an IRELATIVE reloc for a locally defined STT_GNU_IFUNC
845+ // symbol. This makes a function address in a PIE executable
846+ // match the address in a shared library that it links against.
847+ Reloc_section* rel_irelative =
848+ target->rel_irelative_section(layout);
849+ unsigned int r_type = elfcpp::R_ARM_IRELATIVE;
850+ rel_irelative->add_symbolless_global_addend(
851+ gsym, r_type, output_section, object,
852+ data_shndx, reloc.get_r_offset());
853+ }
854+ else if ((r_type == elfcpp::R_ARM_ABS32
855+ || r_type == elfcpp::R_ARM_ABS32_NOI)
856 && gsym->can_use_relative_reloc(false))
857 {
858 Reloc_section* rel_dyn = target->rel_dyn_section(layout);
859@@ -8442,7 +8904,13 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
860 Arm_output_data_got<big_endian>* got =
861 target->got_section(symtab, layout);
862 if (gsym->final_value_is_known())
863- got->add_global(gsym, GOT_TYPE_STANDARD);
864+ {
865+ // For a STT_GNU_IFUNC symbol we want the PLT address.
866+ if (gsym->type() == elfcpp::STT_GNU_IFUNC)
867+ got->add_global_plt(gsym, GOT_TYPE_STANDARD);
868+ else
869+ got->add_global(gsym, GOT_TYPE_STANDARD);
870+ }
871 else
872 {
873 // If this symbol is not fully resolved, we need to add a
874@@ -8452,12 +8920,29 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
875 || gsym->is_undefined()
876 || gsym->is_preemptible()
877 || (gsym->visibility() == elfcpp::STV_PROTECTED
878- && parameters->options().shared()))
879+ && parameters->options().shared())
880+ || (gsym->type() == elfcpp::STT_GNU_IFUNC
881+ && parameters->options().output_is_position_independent()))
882 got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
883 rel_dyn, elfcpp::R_ARM_GLOB_DAT);
884 else
885 {
886- if (got->add_global(gsym, GOT_TYPE_STANDARD))
887+ // For a STT_GNU_IFUNC symbol we want to write the PLT
888+ // offset into the GOT, so that function pointer
889+ // comparisons work correctly.
890+ bool is_new;
891+ if (gsym->type() != elfcpp::STT_GNU_IFUNC)
892+ is_new = got->add_global(gsym, GOT_TYPE_STANDARD);
893+ else
894+ {
895+ is_new = got->add_global_plt(gsym, GOT_TYPE_STANDARD);
896+ // Tell the dynamic linker to use the PLT address
897+ // when resolving relocations.
898+ if (gsym->is_from_dynobj()
899+ && !parameters->options().shared())
900+ gsym->set_needs_dynsym_value();
901+ }
902+ if (is_new)
903 rel_dyn->add_global_relative(
904 gsym, elfcpp::R_ARM_RELATIVE, got,
905 gsym->got_offset(GOT_TYPE_STANDARD));
906@@ -8919,8 +9404,7 @@ Target_arm<big_endian>::Relocate::relocate(
907 if (gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
908 {
909 // This uses a PLT, change the symbol value.
910- symval.set_output_value(target->plt_section()->address()
911- + gsym->plt_offset());
912+ symval.set_output_value(target->plt_address_for_global(gsym));
913 psymval = &symval;
914 }
915 else if (gsym->is_weak_undefined())
916@@ -8958,6 +9442,13 @@ Target_arm<big_endian>::Relocate::relocate(
917 elfcpp::Elf_types<32>::Elf_WXword r_info = rel.get_r_info();
918 unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
919 thumb_bit = object->local_symbol_is_thumb_function(r_sym) ? 1 : 0;
920+
921+ if (psymval->is_ifunc_symbol() && object->local_has_plt_offset(r_sym))
922+ {
923+ symval.set_output_value(
924+ target->plt_address_for_local(object, r_sym));
925+ psymval = &symval;
926+ }
927 }
928 }
929 else
930@@ -9936,7 +10427,7 @@ uint64_t
931 Target_arm<big_endian>::do_dynsym_value(const Symbol* gsym) const
932 {
933 gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
934- return this->plt_section()->address() + gsym->plt_offset();
935+ return this->plt_address_for_global(gsym);
936 }
937
938 // Map platform-specific relocs to real relocs
939@@ -11083,8 +11574,7 @@ Target_arm<big_endian>::scan_reloc_for_stub(
940 if (gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
941 {
942 // This uses a PLT, change the symbol value.
943- symval.set_output_value(this->plt_section()->address()
944- + gsym->plt_offset());
945+ symval.set_output_value(this->plt_address_for_global(gsym));
946 psymval = &symval;
947 target_is_thumb = false;
948 }
949@@ -12187,8 +12677,13 @@ class Target_arm_nacl : public Target_arm<big_endian>
950
951 protected:
952 virtual Output_data_plt_arm<big_endian>*
953- do_make_data_plt(Layout* layout, Output_data_space* got_plt)
954- { return new Output_data_plt_arm_nacl<big_endian>(layout, got_plt); }
955+ do_make_data_plt(
956+ Layout* layout,
957+ Arm_output_data_got<big_endian>* got,
958+ Output_data_space* got_plt,
959+ Output_data_space* got_irelative)
960+ { return new Output_data_plt_arm_nacl<big_endian>(
961+ layout, got, got_plt, got_irelative); }
962
963 private:
964 static const Target::Target_info arm_nacl_info;
965@@ -12225,8 +12720,12 @@ template<bool big_endian>
966 class Output_data_plt_arm_nacl : public Output_data_plt_arm<big_endian>
967 {
968 public:
969- Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt)
970- : Output_data_plt_arm<big_endian>(layout, 16, got_plt)
971+ Output_data_plt_arm_nacl(
972+ Layout* layout,
973+ Arm_output_data_got<big_endian>* got,
974+ Output_data_space* got_plt,
975+ Output_data_space* got_irelative)
976+ : Output_data_plt_arm<big_endian>(layout, 16, got, got_plt, got_irelative)
977 { }
978
979 protected:
980diff --git a/gold/output.h b/gold/output.h
981index ba0cdaa..599c2b7 100644
982--- a/gold/output.h
983+++ b/gold/output.h
984@@ -1714,6 +1714,17 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
985 address, true, true, false, false));
986 }
987
988+ void
989+ add_local_relative(Sized_relobj<size, big_endian>* relobj,
990+ unsigned int local_sym_index, unsigned int type,
991+ Output_data* od, unsigned int shndx, Address address,
992+ bool use_plt_offset)
993+ {
994+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
995+ address, true, true, false,
996+ use_plt_offset));
997+ }
998+
999 // Add a local relocation which does not use a symbol for the relocation,
1000 // but which gets its addend from a symbol.
1001
1002--
10032.7.0
1004