]> git.ipfire.org Git - thirdparty/openembedded/openembedded-core-contrib.git/blob
dcac308bccc0ed03ca691ea0832aae5fd58d41c8
[thirdparty/openembedded/openembedded-core-contrib.git] /
1 From b780c9e06cabe6d8e301aaf46f33f116f3224021 Mon Sep 17 00:00:00 2001
2 From: Han Shen <shenhan@google.com>
3 Date: Thu, 29 Jan 2015 10:00:46 -0800
4 Subject: [PATCH] This patch adds IFUNC support for arm gold backend.
5
6 This is a feature required in chromeos arm development work.
7
8 Tested:
9 1) Built passed all-gold on x86_64 machine
10 2) 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 ---
18 Upstream-Status: Backport
19 Signed-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
27 diff --git a/elfcpp/arm.h b/elfcpp/arm.h
28 index 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.
46 diff --git a/gold/aarch64.cc b/gold/aarch64.cc
47 index 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
59 diff --git a/gold/arm.cc b/gold/arm.cc
60 index 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:
980 diff --git a/gold/output.h b/gold/output.h
981 index 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 --
1003 2.7.0
1004