diff options
author | Khem Raj <raj.khem@gmail.com> | 2016-01-14 03:58:10 -0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-01-24 09:40:31 +0000 |
commit | 136db70700ce198f793935d0683ce4e1f1acf471 (patch) | |
tree | 4d197ae3c35c91a8dee182f21158873abd6e1fa5 | |
parent | 704e34213ed2925ab3ac135717861c4ff466e8ab (diff) | |
download | poky-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>
-rw-r--r-- | meta/recipes-devtools/binutils/binutils-2.25.1.inc | 1 | ||||
-rw-r--r-- | meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch | 1004 |
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 @@ | |||
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 | |||