diff options
Diffstat (limited to 'tools/toolchain-patches/binutils-2.20.1-ld-thumb-interwork-long-call.diff')
-rw-r--r-- | tools/toolchain-patches/binutils-2.20.1-ld-thumb-interwork-long-call.diff | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/tools/toolchain-patches/binutils-2.20.1-ld-thumb-interwork-long-call.diff b/tools/toolchain-patches/binutils-2.20.1-ld-thumb-interwork-long-call.diff new file mode 100644 index 0000000000..5eb5debfbf --- /dev/null +++ b/tools/toolchain-patches/binutils-2.20.1-ld-thumb-interwork-long-call.diff | |||
@@ -0,0 +1,569 @@ | |||
1 | http://sourceware.org/ml/binutils/2010-02/msg00460.html | ||
2 | |||
3 | Drop this patch when binutils 2.21 is out | ||
4 | diff -ur binutils-2.20.1.orig/bfd/elf32-arm.c binutils-2.20.1/bfd/elf32-arm.c | ||
5 | --- binutils-2.20.1.orig/bfd/elf32-arm.c 2010-06-11 18:48:06.000000000 +0200 | ||
6 | +++ binutils-2.20.1/bfd/elf32-arm.c 2010-06-11 18:51:00.000000000 +0200 | ||
7 | @@ -2401,6 +2401,7 @@ | ||
8 | unsigned long orig_insn; | ||
9 | char *stub_name; | ||
10 | enum elf32_arm_stub_type stub_type; | ||
11 | + int st_type; | ||
12 | }; | ||
13 | |||
14 | /* A table of relocs applied to branches which might trigger Cortex-A8 | ||
15 | @@ -2647,6 +2648,9 @@ | ||
16 | asection *stub_sec; | ||
17 | } *stub_group; | ||
18 | |||
19 | + /* Number of elements in stub_group. */ | ||
20 | + int top_id; | ||
21 | + | ||
22 | /* Assorted information used by elf32_arm_size_stubs. */ | ||
23 | unsigned int bfd_count; | ||
24 | int top_index; | ||
25 | @@ -2933,6 +2937,7 @@ | ||
26 | ret->add_stub_section = NULL; | ||
27 | ret->layout_sections_again = NULL; | ||
28 | ret->stub_group = NULL; | ||
29 | + ret->top_id = 0; | ||
30 | ret->bfd_count = 0; | ||
31 | ret->top_index = 0; | ||
32 | ret->input_list = NULL; | ||
33 | @@ -3033,7 +3038,7 @@ | ||
34 | arm_type_of_stub (struct bfd_link_info *info, | ||
35 | asection *input_sec, | ||
36 | const Elf_Internal_Rela *rel, | ||
37 | - unsigned char st_type, | ||
38 | + int *actual_st_type, | ||
39 | struct elf32_arm_link_hash_entry *hash, | ||
40 | bfd_vma destination, | ||
41 | asection *sym_sec, | ||
42 | @@ -3048,6 +3053,7 @@ | ||
43 | int thumb_only; | ||
44 | enum elf32_arm_stub_type stub_type = arm_stub_none; | ||
45 | int use_plt = 0; | ||
46 | + int st_type = *actual_st_type; | ||
47 | |||
48 | /* We don't know the actual type of destination in case it is of | ||
49 | type STT_SECTION: give up. */ | ||
50 | @@ -3065,14 +3071,15 @@ | ||
51 | + input_sec->output_section->vma | ||
52 | + rel->r_offset); | ||
53 | |||
54 | - branch_offset = (bfd_signed_vma)(destination - location); | ||
55 | - | ||
56 | r_type = ELF32_R_TYPE (rel->r_info); | ||
57 | |||
58 | /* Keep a simpler condition, for the sake of clarity. */ | ||
59 | - if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1) | ||
60 | + if (globals->splt != NULL | ||
61 | + && hash != NULL | ||
62 | + && hash->root.plt.offset != (bfd_vma) -1) | ||
63 | { | ||
64 | use_plt = 1; | ||
65 | + | ||
66 | /* Note when dealing with PLT entries: the main PLT stub is in | ||
67 | ARM mode, so if the branch is in Thumb mode, another | ||
68 | Thumb->ARM stub will be inserted later just before the ARM | ||
69 | @@ -3081,8 +3088,15 @@ | ||
70 | Thumb->Arm one and branch directly to the ARM PLT entry | ||
71 | because it avoids spreading offset corrections in several | ||
72 | places. */ | ||
73 | + | ||
74 | + destination = (globals->splt->output_section->vma | ||
75 | + + globals->splt->output_offset | ||
76 | + + hash->root.plt.offset); | ||
77 | + st_type = STT_FUNC; | ||
78 | } | ||
79 | |||
80 | + branch_offset = (bfd_signed_vma)(destination - location); | ||
81 | + | ||
82 | if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) | ||
83 | { | ||
84 | /* Handle cases where: | ||
85 | @@ -3176,7 +3190,9 @@ | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | - else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32) | ||
90 | + else if (r_type == R_ARM_CALL | ||
91 | + || r_type == R_ARM_JUMP24 | ||
92 | + || r_type == R_ARM_PLT32) | ||
93 | { | ||
94 | if (st_type == STT_ARM_TFUNC) | ||
95 | { | ||
96 | @@ -3231,6 +3247,12 @@ | ||
97 | } | ||
98 | } | ||
99 | |||
100 | + /* If a stub is needed, record the actual destination type. */ | ||
101 | + if (stub_type != arm_stub_none) | ||
102 | + { | ||
103 | + *actual_st_type = st_type; | ||
104 | + } | ||
105 | + | ||
106 | return stub_type; | ||
107 | } | ||
108 | |||
109 | @@ -3240,31 +3262,35 @@ | ||
110 | elf32_arm_stub_name (const asection *input_section, | ||
111 | const asection *sym_sec, | ||
112 | const struct elf32_arm_link_hash_entry *hash, | ||
113 | - const Elf_Internal_Rela *rel) | ||
114 | + const Elf_Internal_Rela *rel, | ||
115 | + enum elf32_arm_stub_type stub_type) | ||
116 | + | ||
117 | { | ||
118 | char *stub_name; | ||
119 | bfd_size_type len; | ||
120 | |||
121 | if (hash) | ||
122 | { | ||
123 | - len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1; | ||
124 | + len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1 + 2 + 1; | ||
125 | stub_name = bfd_malloc (len); | ||
126 | if (stub_name != NULL) | ||
127 | - sprintf (stub_name, "%08x_%s+%x", | ||
128 | + sprintf (stub_name, "%08x_%s+%x_%d", | ||
129 | input_section->id & 0xffffffff, | ||
130 | hash->root.root.root.string, | ||
131 | - (int) rel->r_addend & 0xffffffff); | ||
132 | + (int) rel->r_addend & 0xffffffff, | ||
133 | + (int) stub_type); | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | - len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; | ||
138 | + len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 2 + 1; | ||
139 | stub_name = bfd_malloc (len); | ||
140 | if (stub_name != NULL) | ||
141 | - sprintf (stub_name, "%08x_%x:%x+%x", | ||
142 | + sprintf (stub_name, "%08x_%x:%x+%x_%d", | ||
143 | input_section->id & 0xffffffff, | ||
144 | sym_sec->id & 0xffffffff, | ||
145 | (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, | ||
146 | - (int) rel->r_addend & 0xffffffff); | ||
147 | + (int) rel->r_addend & 0xffffffff, | ||
148 | + (int) stub_type); | ||
149 | } | ||
150 | |||
151 | return stub_name; | ||
152 | @@ -3278,7 +3304,8 @@ | ||
153 | const asection *sym_sec, | ||
154 | struct elf_link_hash_entry *hash, | ||
155 | const Elf_Internal_Rela *rel, | ||
156 | - struct elf32_arm_link_hash_table *htab) | ||
157 | + struct elf32_arm_link_hash_table *htab, | ||
158 | + enum elf32_arm_stub_type stub_type) | ||
159 | { | ||
160 | struct elf32_arm_stub_hash_entry *stub_entry; | ||
161 | struct elf32_arm_link_hash_entry *h = (struct elf32_arm_link_hash_entry *) hash; | ||
162 | @@ -3296,7 +3323,8 @@ | ||
163 | |||
164 | if (h != NULL && h->stub_cache != NULL | ||
165 | && h->stub_cache->h == h | ||
166 | - && h->stub_cache->id_sec == id_sec) | ||
167 | + && h->stub_cache->id_sec == id_sec | ||
168 | + && h->stub_cache->stub_type == stub_type) | ||
169 | { | ||
170 | stub_entry = h->stub_cache; | ||
171 | } | ||
172 | @@ -3304,7 +3332,7 @@ | ||
173 | { | ||
174 | char *stub_name; | ||
175 | |||
176 | - stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel); | ||
177 | + stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel, stub_type); | ||
178 | if (stub_name == NULL) | ||
179 | return NULL; | ||
180 | |||
181 | @@ -3464,7 +3492,7 @@ | ||
182 | /* We have to do the a8 fixes last, as they are less aligned than | ||
183 | the other veneers. */ | ||
184 | return TRUE; | ||
185 | - | ||
186 | + | ||
187 | /* Make a note of the offset within the stubs for this entry. */ | ||
188 | stub_entry->stub_offset = stub_sec->size; | ||
189 | loc = stub_sec->contents + stub_entry->stub_offset; | ||
190 | @@ -3499,17 +3527,17 @@ | ||
191 | BFD_ASSERT ((data & 0xff00) == 0xd000); | ||
192 | data |= ((stub_entry->orig_insn >> 22) & 0xf) << 8; | ||
193 | } | ||
194 | - put_thumb_insn (globals, stub_bfd, data, loc + size); | ||
195 | + bfd_put_16 (stub_bfd, data, loc + size); | ||
196 | size += 2; | ||
197 | } | ||
198 | break; | ||
199 | |||
200 | case THUMB32_TYPE: | ||
201 | - put_thumb_insn (globals, stub_bfd, | ||
202 | - (template_sequence[i].data >> 16) & 0xffff, | ||
203 | - loc + size); | ||
204 | - put_thumb_insn (globals, stub_bfd, template_sequence[i].data & 0xffff, | ||
205 | - loc + size + 2); | ||
206 | + bfd_put_16 (stub_bfd, | ||
207 | + (template_sequence[i].data >> 16) & 0xffff, | ||
208 | + loc + size); | ||
209 | + bfd_put_16 (stub_bfd, template_sequence[i].data & 0xffff, | ||
210 | + loc + size + 2); | ||
211 | if (template_sequence[i].r_type != R_ARM_NONE) | ||
212 | { | ||
213 | stub_reloc_idx[nrelocs] = i; | ||
214 | @@ -3519,8 +3547,8 @@ | ||
215 | break; | ||
216 | |||
217 | case ARM_TYPE: | ||
218 | - put_arm_insn (globals, stub_bfd, template_sequence[i].data, | ||
219 | - loc + size); | ||
220 | + bfd_put_32 (stub_bfd, template_sequence[i].data, | ||
221 | + loc + size); | ||
222 | /* Handle cases where the target is encoded within the | ||
223 | instruction. */ | ||
224 | if (template_sequence[i].r_type == R_ARM_JUMP24) | ||
225 | @@ -3599,11 +3627,23 @@ | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | - _bfd_final_link_relocate (elf32_arm_howto_from_type | ||
230 | - (template_sequence[stub_reloc_idx[i]].r_type), stub_bfd, stub_sec, | ||
231 | - stub_sec->contents, stub_entry->stub_offset + stub_reloc_offset[i], | ||
232 | - sym_value + stub_entry->target_addend, | ||
233 | - template_sequence[stub_reloc_idx[i]].reloc_addend); | ||
234 | + Elf_Internal_Rela rel; | ||
235 | + bfd_boolean unresolved_reloc; | ||
236 | + char *error_message; | ||
237 | + bfd_vma points_to = sym_value + stub_entry->target_addend | ||
238 | + + template_sequence[stub_reloc_idx[i]].reloc_addend; | ||
239 | + | ||
240 | + rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i]; | ||
241 | + rel.r_info = ELF32_R_INFO (0, | ||
242 | + template_sequence[stub_reloc_idx[i]].r_type); | ||
243 | + rel.r_addend = 0; | ||
244 | + | ||
245 | + elf32_arm_final_link_relocate (elf32_arm_howto_from_type | ||
246 | + (template_sequence[stub_reloc_idx[i]].r_type), | ||
247 | + stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel, | ||
248 | + points_to, info, stub_entry->target_section, "", stub_entry->st_type, | ||
249 | + (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc, | ||
250 | + &error_message); | ||
251 | } | ||
252 | |||
253 | return TRUE; | ||
254 | @@ -3728,6 +3768,7 @@ | ||
255 | htab->stub_group = bfd_zmalloc (amt); | ||
256 | if (htab->stub_group == NULL) | ||
257 | return -1; | ||
258 | + htab->top_id = top_id; | ||
259 | |||
260 | /* We can't use output_bfd->section_count here to find the top output | ||
261 | section index as some sections may have been removed, and | ||
262 | @@ -4009,7 +4050,7 @@ | ||
263 | } | ||
264 | |||
265 | is_32bit_branch = is_b || is_bl || is_blx || is_bcc; | ||
266 | - | ||
267 | + | ||
268 | if (((base_vma + i) & 0xfff) == 0xffe | ||
269 | && insn_32bit | ||
270 | && is_32bit_branch | ||
271 | @@ -4178,6 +4219,8 @@ | ||
272 | a8_fixes[num_a8_fixes].orig_insn = insn; | ||
273 | a8_fixes[num_a8_fixes].stub_name = stub_name; | ||
274 | a8_fixes[num_a8_fixes].stub_type = stub_type; | ||
275 | + a8_fixes[num_a8_fixes].st_type = | ||
276 | + is_blx ? STT_FUNC : STT_ARM_TFUNC; | ||
277 | |||
278 | num_a8_fixes++; | ||
279 | } | ||
280 | @@ -4193,11 +4236,11 @@ | ||
281 | if (elf_section_data (section)->this_hdr.contents == NULL) | ||
282 | free (contents); | ||
283 | } | ||
284 | - | ||
285 | + | ||
286 | *a8_fixes_p = a8_fixes; | ||
287 | *num_a8_fixes_p = num_a8_fixes; | ||
288 | *a8_fix_table_size_p = a8_fix_table_size; | ||
289 | - | ||
290 | + | ||
291 | return FALSE; | ||
292 | } | ||
293 | |||
294 | @@ -4345,7 +4388,7 @@ | ||
295 | const char *sym_name; | ||
296 | char *stub_name; | ||
297 | const asection *id_sec; | ||
298 | - unsigned char st_type; | ||
299 | + int st_type; | ||
300 | bfd_boolean created_stub = FALSE; | ||
301 | |||
302 | r_type = ELF32_R_TYPE (irela->r_info); | ||
303 | @@ -4403,7 +4446,7 @@ | ||
304 | /* This is an undefined symbol. It can never | ||
305 | be resolved. */ | ||
306 | continue; | ||
307 | - | ||
308 | + | ||
309 | if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) | ||
310 | sym_value = sym->st_value; | ||
311 | destination = (sym_value + irela->r_addend | ||
312 | @@ -4493,7 +4536,7 @@ | ||
313 | { | ||
314 | /* Determine what (if any) linker stub is needed. */ | ||
315 | stub_type = arm_type_of_stub (info, section, irela, | ||
316 | - st_type, hash, | ||
317 | + &st_type, hash, | ||
318 | destination, sym_sec, | ||
319 | input_bfd, sym_name); | ||
320 | if (stub_type == arm_stub_none) | ||
321 | @@ -4504,7 +4547,7 @@ | ||
322 | |||
323 | /* Get the name of this stub. */ | ||
324 | stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash, | ||
325 | - irela); | ||
326 | + irela, stub_type); | ||
327 | if (!stub_name) | ||
328 | goto error_ret_free_internal; | ||
329 | |||
330 | @@ -4703,7 +4746,7 @@ | ||
331 | stub_entry->target_value = a8_fixes[i].offset; | ||
332 | stub_entry->target_addend = a8_fixes[i].addend; | ||
333 | stub_entry->orig_insn = a8_fixes[i].orig_insn; | ||
334 | - stub_entry->st_type = STT_ARM_TFUNC; | ||
335 | + stub_entry->st_type = a8_fixes[i].st_type; | ||
336 | |||
337 | size = find_stub_size_and_template (a8_fixes[i].stub_type, | ||
338 | &template_sequence, | ||
339 | @@ -6866,6 +6909,7 @@ | ||
340 | ".tls_vars") == 0) | ||
341 | && ((r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI) | ||
342 | || !SYMBOL_CALLS_LOCAL (info, h)) | ||
343 | + && (!strstr (input_section->name, STUB_SUFFIX)) | ||
344 | && (h == NULL | ||
345 | || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT | ||
346 | || h->root.type != bfd_link_hash_undefweak) | ||
347 | @@ -6990,7 +7034,6 @@ | ||
348 | case R_ARM_PC24: /* Arm B/BL instruction. */ | ||
349 | case R_ARM_PLT32: | ||
350 | { | ||
351 | - bfd_signed_vma branch_offset; | ||
352 | struct elf32_arm_stub_hash_entry *stub_entry = NULL; | ||
353 | |||
354 | if (r_type == R_ARM_XPC25) | ||
355 | @@ -7026,45 +7069,46 @@ | ||
356 | || r_type == R_ARM_JUMP24 | ||
357 | || r_type == R_ARM_PLT32) | ||
358 | { | ||
359 | - bfd_vma from; | ||
360 | - | ||
361 | - /* If the call goes through a PLT entry, make sure to | ||
362 | - check distance to the right destination address. */ | ||
363 | - if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) | ||
364 | - { | ||
365 | - value = (splt->output_section->vma | ||
366 | - + splt->output_offset | ||
367 | - + h->plt.offset); | ||
368 | - *unresolved_reloc_p = FALSE; | ||
369 | - /* The PLT entry is in ARM mode, regardless of the | ||
370 | - target function. */ | ||
371 | - sym_flags = STT_FUNC; | ||
372 | - } | ||
373 | + enum elf32_arm_stub_type stub_type = arm_stub_none; | ||
374 | + struct elf32_arm_link_hash_entry *hash; | ||
375 | |||
376 | - from = (input_section->output_section->vma | ||
377 | - + input_section->output_offset | ||
378 | - + rel->r_offset); | ||
379 | - branch_offset = (bfd_signed_vma)(value - from); | ||
380 | - | ||
381 | - if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET | ||
382 | - || branch_offset < ARM_MAX_BWD_BRANCH_OFFSET | ||
383 | - || ((sym_flags == STT_ARM_TFUNC) | ||
384 | - && (((r_type == R_ARM_CALL) && !globals->use_blx) | ||
385 | - || (r_type == R_ARM_JUMP24) | ||
386 | - || (r_type == R_ARM_PLT32) )) | ||
387 | - ) | ||
388 | + hash = (struct elf32_arm_link_hash_entry *) h; | ||
389 | + stub_type = arm_type_of_stub (info, input_section, rel, | ||
390 | + &sym_flags, hash, | ||
391 | + value, sym_sec, | ||
392 | + input_bfd, sym_name); | ||
393 | + | ||
394 | + if (stub_type != arm_stub_none) | ||
395 | { | ||
396 | /* The target is out of reach, so redirect the | ||
397 | branch to the local stub for this function. */ | ||
398 | |||
399 | stub_entry = elf32_arm_get_stub_entry (input_section, | ||
400 | sym_sec, h, | ||
401 | - rel, globals); | ||
402 | + rel, globals, | ||
403 | + stub_type); | ||
404 | if (stub_entry != NULL) | ||
405 | value = (stub_entry->stub_offset | ||
406 | + stub_entry->stub_sec->output_offset | ||
407 | + stub_entry->stub_sec->output_section->vma); | ||
408 | } | ||
409 | + else | ||
410 | + { | ||
411 | + /* If the call goes through a PLT entry, make sure to | ||
412 | + check distance to the right destination address. */ | ||
413 | + if (h != NULL | ||
414 | + && splt != NULL | ||
415 | + && h->plt.offset != (bfd_vma) -1) | ||
416 | + { | ||
417 | + value = (splt->output_section->vma | ||
418 | + + splt->output_offset | ||
419 | + + h->plt.offset); | ||
420 | + *unresolved_reloc_p = FALSE; | ||
421 | + /* The PLT entry is in ARM mode, regardless of the | ||
422 | + target function. */ | ||
423 | + sym_flags = STT_FUNC; | ||
424 | + } | ||
425 | + } | ||
426 | } | ||
427 | |||
428 | /* The ARM ELF ABI says that this reloc is computed as: S - P + A | ||
429 | @@ -7444,58 +7488,29 @@ | ||
430 | } | ||
431 | } | ||
432 | |||
433 | - /* Handle calls via the PLT. */ | ||
434 | - if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) | ||
435 | - { | ||
436 | - value = (splt->output_section->vma | ||
437 | - + splt->output_offset | ||
438 | - + h->plt.offset); | ||
439 | - if (globals->use_blx && r_type == R_ARM_THM_CALL) | ||
440 | - { | ||
441 | - /* If the Thumb BLX instruction is available, convert the | ||
442 | - BL to a BLX instruction to call the ARM-mode PLT entry. */ | ||
443 | - lower_insn = (lower_insn & ~0x1000) | 0x0800; | ||
444 | - sym_flags = STT_FUNC; | ||
445 | - } | ||
446 | - else | ||
447 | - { | ||
448 | - /* Target the Thumb stub before the ARM PLT entry. */ | ||
449 | - value -= PLT_THUMB_STUB_SIZE; | ||
450 | - sym_flags = STT_ARM_TFUNC; | ||
451 | - } | ||
452 | - *unresolved_reloc_p = FALSE; | ||
453 | - } | ||
454 | - | ||
455 | + enum elf32_arm_stub_type stub_type = arm_stub_none; | ||
456 | if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) | ||
457 | { | ||
458 | /* Check if a stub has to be inserted because the destination | ||
459 | is too far. */ | ||
460 | - bfd_vma from; | ||
461 | - bfd_signed_vma branch_offset; | ||
462 | - struct elf32_arm_stub_hash_entry *stub_entry = NULL; | ||
463 | - | ||
464 | - from = (input_section->output_section->vma | ||
465 | - + input_section->output_offset | ||
466 | - + rel->r_offset); | ||
467 | - branch_offset = (bfd_signed_vma)(value - from); | ||
468 | - | ||
469 | - if ((!thumb2 | ||
470 | - && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET | ||
471 | - || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET))) | ||
472 | - || | ||
473 | - (thumb2 | ||
474 | - && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET | ||
475 | - || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) | ||
476 | - || ((sym_flags != STT_ARM_TFUNC) | ||
477 | - && (((r_type == R_ARM_THM_CALL) && !globals->use_blx) | ||
478 | - || r_type == R_ARM_THM_JUMP24))) | ||
479 | + struct elf32_arm_stub_hash_entry *stub_entry; | ||
480 | + struct elf32_arm_link_hash_entry *hash; | ||
481 | + | ||
482 | + hash = (struct elf32_arm_link_hash_entry *) h; | ||
483 | + | ||
484 | + stub_type = arm_type_of_stub (info, input_section, rel, | ||
485 | + &sym_flags, hash, value, sym_sec, | ||
486 | + input_bfd, sym_name); | ||
487 | + | ||
488 | + if (stub_type != arm_stub_none) | ||
489 | { | ||
490 | /* The target is out of reach or we are changing modes, so | ||
491 | redirect the branch to the local stub for this | ||
492 | function. */ | ||
493 | stub_entry = elf32_arm_get_stub_entry (input_section, | ||
494 | sym_sec, h, | ||
495 | - rel, globals); | ||
496 | + rel, globals, | ||
497 | + stub_type); | ||
498 | if (stub_entry != NULL) | ||
499 | value = (stub_entry->stub_offset | ||
500 | + stub_entry->stub_sec->output_offset | ||
501 | @@ -7512,6 +7527,33 @@ | ||
502 | } | ||
503 | } | ||
504 | |||
505 | + /* Handle calls via the PLT. */ | ||
506 | + if (stub_type == arm_stub_none | ||
507 | + && h != NULL | ||
508 | + && splt != NULL | ||
509 | + && h->plt.offset != (bfd_vma) -1) | ||
510 | + { | ||
511 | + value = (splt->output_section->vma | ||
512 | + + splt->output_offset | ||
513 | + + h->plt.offset); | ||
514 | + | ||
515 | + if (globals->use_blx && r_type == R_ARM_THM_CALL) | ||
516 | + { | ||
517 | + /* If the Thumb BLX instruction is available, convert | ||
518 | + the BL to a BLX instruction to call the ARM-mode | ||
519 | + PLT entry. */ | ||
520 | + lower_insn = (lower_insn & ~0x1000) | 0x0800; | ||
521 | + sym_flags = STT_FUNC; | ||
522 | + } | ||
523 | + else | ||
524 | + { | ||
525 | + /* Target the Thumb stub before the ARM PLT entry. */ | ||
526 | + value -= PLT_THUMB_STUB_SIZE; | ||
527 | + sym_flags = STT_ARM_TFUNC; | ||
528 | + } | ||
529 | + *unresolved_reloc_p = FALSE; | ||
530 | + } | ||
531 | + | ||
532 | relocation = value + signed_addend; | ||
533 | |||
534 | relocation -= (input_section->output_section->vma | ||
535 | @@ -9298,11 +9340,26 @@ | ||
536 | elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info) | ||
537 | { | ||
538 | struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info); | ||
539 | + asection *sec, *osec; | ||
540 | |||
541 | /* Invoke the regular ELF backend linker to do all the work. */ | ||
542 | if (!bfd_elf_final_link (abfd, info)) | ||
543 | return FALSE; | ||
544 | |||
545 | + /* Process stub sections (eg BE8 encoding, ...). */ | ||
546 | + struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); | ||
547 | + int i; | ||
548 | + for(i=0; i<htab->top_id; i++) { | ||
549 | + sec = htab->stub_group[i].stub_sec; | ||
550 | + if (sec) { | ||
551 | + osec = sec->output_section; | ||
552 | + elf32_arm_write_section (abfd, info, sec, sec->contents); | ||
553 | + if (! bfd_set_section_contents (abfd, osec, sec->contents, | ||
554 | + sec->output_offset, sec->size)) | ||
555 | + return FALSE; | ||
556 | + } | ||
557 | + } | ||
558 | + | ||
559 | /* Write out any glue sections now that we have created all the | ||
560 | stubs. */ | ||
561 | if (globals->bfd_of_glue_owner != NULL) | ||
562 | @@ -12875,6 +12932,7 @@ | ||
563 | sym.st_other = 0; | ||
564 | sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); | ||
565 | sym.st_shndx = osi->sec_shndx; | ||
566 | + elf32_arm_section_map_add (osi->sec, names[type][1], offset); | ||
567 | return osi->func (osi->finfo, names[type], &sym, osi->sec, NULL) == 1; | ||
568 | } | ||
569 | |||