Update year range in copyright notice of binutils files
[deliverable/binutils-gdb.git] / bfd / elf32-ft32.c
1 /* ft32-specific support for 32-bit ELF.
2 Copyright (C) 2013-2019 Free Software Foundation, Inc.
3
4 Copied from elf32-moxie.c which is..
5 Copyright (C) 2009-2019 Free Software Foundation, Inc.
6 Free Software Foundation, Inc.
7
8 This file is part of BFD, the Binary File Descriptor library.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
23 MA 02110-1301, USA. */
24
25 #include "sysdep.h"
26 #include "bfd.h"
27 #include "libbfd.h"
28 #include "elf-bfd.h"
29 #include "elf/ft32.h"
30 #include "opcode/ft32.h"
31
32 static bfd_boolean debug_relax = FALSE;
33
34 static bfd_reloc_status_type
35 bfd_elf_ft32_diff_reloc (bfd *, arelent *, asymbol *, void *,
36 asection *, bfd *, char **);
37
38 static reloc_howto_type ft32_elf_howto_table [] =
39 {
40 /* This reloc does nothing. */
41 HOWTO (R_FT32_NONE, /* type */
42 0, /* rightshift */
43 2, /* size (0 = byte, 1 = short, 2 = long) */
44 32, /* bitsize */
45 FALSE, /* pc_relative */
46 0, /* bitpos */
47 complain_overflow_bitfield, /* complain_on_overflow */
48 bfd_elf_generic_reloc, /* special_function */
49 "R_FT32_NONE", /* name */
50 FALSE, /* partial_inplace */
51 0, /* src_mask */
52 0, /* dst_mask */
53 FALSE), /* pcrel_offset */
54
55 /* A 32 bit absolute relocation. */
56
57 HOWTO (R_FT32_32, /* type */
58 0, /* rightshift */
59 2, /* size (0 = byte, 1 = short, 2 = long) */
60 32, /* bitsize */
61 FALSE, /* pc_relative */
62 0, /* bitpos */
63 complain_overflow_bitfield, /* complain_on_overflow */
64 bfd_elf_generic_reloc, /* special_function */
65 "R_FT32_32", /* name */
66 FALSE, /* partial_inplace */
67 0x00000000, /* src_mask */
68 0xffffffff, /* dst_mask */
69 FALSE), /* pcrel_offset */
70
71 HOWTO (R_FT32_16, /* type */
72 0, /* rightshift */
73 1, /* size (0 = byte, 1 = short, 2 = long) */
74 16, /* bitsize */
75 FALSE, /* pc_relative */
76 0, /* bitpos */
77 complain_overflow_dont, /* complain_on_overflow */
78 bfd_elf_generic_reloc, /* special_function */
79 "R_FT32_16", /* name */
80 FALSE, /* partial_inplace */
81 0x00000000, /* src_mask */
82 0x0000ffff, /* dst_mask */
83 FALSE), /* pcrel_offset */
84
85 HOWTO (R_FT32_8, /* type */
86 0, /* rightshift */
87 0, /* size (0 = byte, 1 = short, 2 = long) */
88 8, /* bitsize */
89 FALSE, /* pc_relative */
90 0, /* bitpos */
91 complain_overflow_signed, /* complain_on_overflow */
92 bfd_elf_generic_reloc, /* special_function */
93 "R_FT32_8", /* name */
94 FALSE, /* partial_inplace */
95 0x00000000, /* src_mask */
96 0x000000ff, /* dst_mask */
97 FALSE), /* pcrel_offset */
98
99 HOWTO (R_FT32_10, /* type */
100 0, /* rightshift */
101 1, /* size (0 = byte, 1 = short, 2 = long) */
102 10, /* bitsize */
103 FALSE, /* pc_relative */
104 4, /* bitpos */
105 complain_overflow_bitfield, /* complain_on_overflow */
106 bfd_elf_generic_reloc, /* special_function */
107 "R_FT32_10", /* name */
108 FALSE, /* partial_inplace */
109 0x00000000, /* src_mask */
110 0x00003ff0, /* dst_mask */
111 FALSE), /* pcrel_offset */
112
113 HOWTO (R_FT32_20, /* type */
114 0, /* rightshift */
115 2, /* size (0 = byte, 1 = short, 2 = long) */
116 20, /* bitsize */
117 FALSE, /* pc_relative */
118 0, /* bitpos */
119 complain_overflow_dont, /* complain_on_overflow */
120 bfd_elf_generic_reloc, /* special_function */
121 "R_FT32_20", /* name */
122 FALSE, /* partial_inplace */
123 0x00000000, /* src_mask */
124 0x000fffff, /* dst_mask */
125 FALSE), /* pcrel_offset */
126
127 HOWTO (R_FT32_17, /* type */
128 0, /* rightshift */
129 2, /* size (0 = byte, 1 = short, 2 = long) */
130 17, /* bitsize */
131 FALSE, /* pc_relative */
132 0, /* bitpos */
133 complain_overflow_dont, /* complain_on_overflow */
134 bfd_elf_generic_reloc, /* special_function */
135 "R_FT32_17", /* name */
136 FALSE, /* partial_inplace */
137 0x00000000, /* src_mask */
138 0x0001ffff, /* dst_mask */
139 FALSE), /* pcrel_offset */
140
141 HOWTO (R_FT32_18, /* type */
142 2, /* rightshift */
143 2, /* size (0 = byte, 1 = short, 2 = long) */
144 18, /* bitsize */
145 FALSE, /* pc_relative */
146 0, /* bitpos */
147 complain_overflow_dont, /* complain_on_overflow */
148 bfd_elf_generic_reloc, /* special_function */
149 "R_FT32_18", /* name */
150 FALSE, /* partial_inplace */
151 0x00000000, /* src_mask */
152 0x0003ffff, /* dst_mask */
153 FALSE), /* pcrel_offset */
154
155 HOWTO (R_FT32_RELAX, /* type */
156 0, /* rightshift */
157 1, /* size (0 = byte, 1 = short, 2 = long) */
158 10, /* bitsize */
159 FALSE, /* pc_relative */
160 4, /* bitpos */
161 complain_overflow_signed, /* complain_on_overflow */
162 bfd_elf_generic_reloc, /* special_function */
163 "R_FT32_RELAX", /* name */
164 FALSE, /* partial_inplace */
165 0x00000000, /* src_mask */
166 0x00000000, /* dst_mask */
167 FALSE), /* pcrel_offset */
168
169 HOWTO (R_FT32_SC0, /* type */
170 0, /* rightshift */
171 1, /* size (0 = byte, 1 = short, 2 = long) */
172 10, /* bitsize */
173 FALSE, /* pc_relative */
174 4, /* bitpos */
175 complain_overflow_signed, /* complain_on_overflow */
176 bfd_elf_generic_reloc, /* special_function */
177 "R_FT32_SC0", /* name */
178 FALSE, /* partial_inplace */
179 0x00000000, /* src_mask */
180 0x00000000, /* dst_mask */
181 FALSE), /* pcrel_offset */
182 HOWTO (R_FT32_SC1, /* type */
183 2, /* rightshift */
184 2, /* size (0 = byte, 1 = short, 2 = long) */
185 22, /* bitsize */
186 TRUE, /* pc_relative */
187 7, /* bitpos */
188 complain_overflow_dont, /* complain_on_overflow */
189 bfd_elf_generic_reloc, /* special_function */
190 "R_FT32_SC1", /* name */
191 TRUE, /* partial_inplace */
192 0x07ffff80, /* src_mask */
193 0x07ffff80, /* dst_mask */
194 FALSE), /* pcrel_offset */
195 HOWTO (R_FT32_15, /* type */
196 0, /* rightshift */
197 2, /* size (0 = byte, 1 = short, 2 = long) */
198 15, /* bitsize */
199 FALSE, /* pc_relative */
200 0, /* bitpos */
201 complain_overflow_dont, /* complain_on_overflow */
202 bfd_elf_generic_reloc, /* special_function */
203 "R_FT32_15", /* name */
204 FALSE, /* partial_inplace */
205 0x00000000, /* src_mask */
206 0x00007fff, /* dst_mask */
207 FALSE), /* pcrel_offset */
208 HOWTO (R_FT32_DIFF32, /* type */
209 0, /* rightshift */
210 2, /* size (0 = byte, 1 = short, 2 = long) */
211 32, /* bitsize */
212 FALSE, /* pc_relative */
213 0, /* bitpos */
214 complain_overflow_dont, /* complain_on_overflow */
215 bfd_elf_ft32_diff_reloc, /* special_function */
216 "R_FT32_DIFF32", /* name */
217 FALSE, /* partial_inplace */
218 0, /* src_mask */
219 0xffffffff, /* dst_mask */
220 FALSE), /* pcrel_offset */
221 };
222 \f
223 \f
224 /* Map BFD reloc types to FT32 ELF reloc types. */
225
226 struct ft32_reloc_map
227 {
228 bfd_reloc_code_real_type bfd_reloc_val;
229 unsigned int ft32_reloc_val;
230 };
231
232 static const struct ft32_reloc_map ft32_reloc_map [] =
233 {
234 { BFD_RELOC_NONE, R_FT32_NONE },
235 { BFD_RELOC_32, R_FT32_32 },
236 { BFD_RELOC_16, R_FT32_16 },
237 { BFD_RELOC_8, R_FT32_8 },
238 { BFD_RELOC_FT32_10, R_FT32_10 },
239 { BFD_RELOC_FT32_20, R_FT32_20 },
240 { BFD_RELOC_FT32_17, R_FT32_17 },
241 { BFD_RELOC_FT32_18, R_FT32_18 },
242 { BFD_RELOC_FT32_RELAX, R_FT32_RELAX },
243 { BFD_RELOC_FT32_SC0, R_FT32_SC0 },
244 { BFD_RELOC_FT32_SC1, R_FT32_SC1 },
245 { BFD_RELOC_FT32_15, R_FT32_15 },
246 { BFD_RELOC_FT32_DIFF32, R_FT32_DIFF32 },
247 };
248
249 /* Perform a diff relocation. Nothing to do, as the difference value is
250 already written into the section's contents. */
251
252 static bfd_reloc_status_type
253 bfd_elf_ft32_diff_reloc (bfd *abfd ATTRIBUTE_UNUSED,
254 arelent *reloc_entry ATTRIBUTE_UNUSED,
255 asymbol *symbol ATTRIBUTE_UNUSED,
256 void *data ATTRIBUTE_UNUSED,
257 asection *input_section ATTRIBUTE_UNUSED,
258 bfd *output_bfd ATTRIBUTE_UNUSED,
259 char **error_message ATTRIBUTE_UNUSED)
260 {
261 return bfd_reloc_ok;
262 }
263
264 static reloc_howto_type *
265 ft32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
266 bfd_reloc_code_real_type code)
267 {
268 unsigned int i;
269
270 for (i = sizeof (ft32_reloc_map) / sizeof (ft32_reloc_map[0]);
271 --i;)
272 if (ft32_reloc_map [i].bfd_reloc_val == code)
273 return & ft32_elf_howto_table [ft32_reloc_map[i].ft32_reloc_val];
274
275 return NULL;
276 }
277
278 static reloc_howto_type *
279 ft32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
280 {
281 unsigned int i;
282
283 for (i = 0;
284 i < sizeof (ft32_elf_howto_table) / sizeof (ft32_elf_howto_table[0]);
285 i++)
286 if (ft32_elf_howto_table[i].name != NULL
287 && strcasecmp (ft32_elf_howto_table[i].name, r_name) == 0)
288 return &ft32_elf_howto_table[i];
289
290 return NULL;
291 }
292
293 /* Set the howto pointer for an FT32 ELF reloc. */
294
295 static bfd_boolean
296 ft32_info_to_howto_rela (bfd *abfd,
297 arelent *cache_ptr,
298 Elf_Internal_Rela *dst)
299 {
300 unsigned int r_type;
301
302 r_type = ELF32_R_TYPE (dst->r_info);
303 if (r_type >= (unsigned int) R_FT32_max)
304 {
305 /* xgettext:c-format */
306 _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
307 abfd, r_type);
308 bfd_set_error (bfd_error_bad_value);
309 return FALSE;
310 }
311
312 cache_ptr->howto = & ft32_elf_howto_table [r_type];
313 return cache_ptr->howto != NULL;
314 }
315
316 /* Relocate an FT32 ELF section.
317
318 The RELOCATE_SECTION function is called by the new ELF backend linker
319 to handle the relocations for a section.
320
321 The relocs are always passed as Rela structures; if the section
322 actually uses Rel structures, the r_addend field will always be
323 zero.
324
325 This function is responsible for adjusting the section contents as
326 necessary, and (if using Rela relocs and generating a relocatable
327 output file) adjusting the reloc addend as necessary.
328
329 This function does not have to worry about setting the reloc
330 address or the reloc symbol index.
331
332 LOCAL_SYMS is a pointer to the swapped in local symbols.
333
334 LOCAL_SECTIONS is an array giving the section in the input file
335 corresponding to the st_shndx field of each local symbol.
336
337 The global hash table entry for the global symbols can be found
338 via elf_sym_hashes (input_bfd).
339
340 When generating relocatable output, this function must handle
341 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
342 going to be the section symbol corresponding to the output
343 section, which means that the addend must be adjusted
344 accordingly. */
345
346 static bfd_boolean
347 ft32_elf_relocate_section (bfd *output_bfd,
348 struct bfd_link_info *info,
349 bfd *input_bfd,
350 asection *input_section,
351 bfd_byte *contents,
352 Elf_Internal_Rela *relocs,
353 Elf_Internal_Sym *local_syms,
354 asection **local_sections)
355 {
356 Elf_Internal_Shdr *symtab_hdr;
357 struct elf_link_hash_entry **sym_hashes;
358 Elf_Internal_Rela *rel;
359 Elf_Internal_Rela *relend;
360
361 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
362 sym_hashes = elf_sym_hashes (input_bfd);
363 relend = relocs + input_section->reloc_count;
364
365 for (rel = relocs; rel < relend; rel ++)
366 {
367 reloc_howto_type *howto;
368 unsigned long r_symndx;
369 Elf_Internal_Sym *sym;
370 asection *sec;
371 struct elf_link_hash_entry *h;
372 bfd_vma relocation;
373 bfd_reloc_status_type r;
374 const char *name;
375 int r_type;
376
377 r_type = ELF32_R_TYPE (rel->r_info);
378 r_symndx = ELF32_R_SYM (rel->r_info);
379 howto = ft32_elf_howto_table + r_type;
380 h = NULL;
381 sym = NULL;
382 sec = NULL;
383
384 if (r_symndx < symtab_hdr->sh_info)
385 {
386 sym = local_syms + r_symndx;
387 sec = local_sections [r_symndx];
388 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
389
390 name = bfd_elf_string_from_elf_section
391 (input_bfd, symtab_hdr->sh_link, sym->st_name);
392 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
393 }
394 else
395 {
396 bfd_boolean unresolved_reloc, warned, ignored;
397
398 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
399 r_symndx, symtab_hdr, sym_hashes,
400 h, sec, relocation,
401 unresolved_reloc, warned, ignored);
402
403 name = h->root.root.string;
404 }
405
406 if (sec != NULL && discarded_section (sec))
407 RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
408 rel, 1, relend, howto, 0, contents);
409
410 if (bfd_link_relocatable (info))
411 continue;
412
413 switch (howto->type)
414 {
415 case R_FT32_SC0:
416 {
417 unsigned int insn;
418 int offset;
419 unsigned int code15[2];
420
421 insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
422 ft32_split_shortcode (insn, code15);
423
424 offset = (int)relocation;
425 offset += (int)(rel->r_addend - rel->r_offset);
426 offset -= (input_section->output_section->vma +
427 input_section->output_offset);
428 if ((offset < -1024) || (offset >= 1024))
429 {
430 r = bfd_reloc_outofrange;
431 break;
432 }
433 code15[0] |= ((offset / 4) & 511);
434 insn = ft32_merge_shortcode (code15);
435 bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
436 }
437 r = bfd_reloc_ok;
438 break;
439
440 case R_FT32_SC1:
441 {
442 unsigned int insn;
443 int offset;
444 unsigned int code15[2];
445
446 insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
447 ft32_split_shortcode (insn, code15);
448
449 offset = (int)relocation;
450 offset += (int)(rel->r_addend - rel->r_offset);
451 offset -= (input_section->output_section->vma +
452 input_section->output_offset);
453 if ((offset < -1024) || (offset >= 1024))
454 {
455 r = bfd_reloc_outofrange;
456 break;
457 }
458 code15[1] |= ((offset / 4) & 511);
459 insn = ft32_merge_shortcode (code15);
460 bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
461 }
462 r = bfd_reloc_ok;
463 break;
464
465 case R_FT32_DIFF32:
466 r = bfd_reloc_ok;
467 break;
468
469 default:
470 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
471 contents, rel->r_offset,
472 relocation, rel->r_addend);
473 break;
474 }
475
476 if (r != bfd_reloc_ok)
477 {
478 const char * msg = NULL;
479
480 switch (r)
481 {
482 case bfd_reloc_overflow:
483 (*info->callbacks->reloc_overflow)
484 (info, (h ? &h->root : NULL), name, howto->name,
485 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
486 break;
487
488 case bfd_reloc_undefined:
489 (*info->callbacks->undefined_symbol)
490 (info, name, input_bfd, input_section, rel->r_offset, TRUE);
491 break;
492
493 case bfd_reloc_outofrange:
494 msg = _("internal error: out of range error");
495 break;
496
497 case bfd_reloc_notsupported:
498 msg = _("internal error: unsupported relocation error");
499 break;
500
501 case bfd_reloc_dangerous:
502 msg = _("internal error: dangerous relocation");
503 break;
504
505 default:
506 msg = _("internal error: unknown error");
507 break;
508 }
509
510 if (msg)
511 (*info->callbacks->warning) (info, msg, name, input_bfd,
512 input_section, rel->r_offset);
513 }
514 }
515
516 return TRUE;
517 }
518 \f
519 /* Relaxation. */
520
521 static bfd_boolean
522 ft32_reloc_shortable
523 (bfd * abfd,
524 asection * sec,
525 Elf_Internal_Sym * isymbuf ATTRIBUTE_UNUSED,
526 bfd_byte * contents,
527 bfd_vma pc ATTRIBUTE_UNUSED,
528 Elf_Internal_Rela * irel,
529 unsigned int * sc)
530 {
531 Elf_Internal_Shdr *symtab_hdr ATTRIBUTE_UNUSED;
532 bfd_vma symval;
533
534 enum elf_ft32_reloc_type r_type;
535 reloc_howto_type *howto = NULL;
536 unsigned int insn;
537 int offset;
538 bfd_vma dot, value;
539
540 r_type = ELF32_R_TYPE (irel->r_info);
541 howto = &ft32_elf_howto_table [r_type];
542
543 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
544
545 /* Get the value of the symbol referred to by the reloc. */
546 if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
547 {
548 /* A local symbol. */
549 Elf_Internal_Sym *isym;
550 asection *sym_sec;
551
552 isym = isymbuf + ELF32_R_SYM (irel->r_info);
553 sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
554 symval = isym->st_value;
555 /* If the reloc is absolute, it will not have
556 a symbol or section associated with it. */
557 if (sym_sec)
558 symval += sym_sec->output_section->vma
559 + sym_sec->output_offset;
560 }
561 else
562 {
563 unsigned long indx;
564 struct elf_link_hash_entry *h;
565
566 /* An external symbol. */
567 indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
568 h = elf_sym_hashes (abfd)[indx];
569 BFD_ASSERT (h != NULL);
570 if (h->root.type != bfd_link_hash_defined
571 && h->root.type != bfd_link_hash_defweak)
572 /* This appears to be a reference to an undefined
573 symbol. Just ignore it--it will be caught by the
574 regular reloc processing. */
575 return FALSE;
576
577 symval = (h->root.u.def.value
578 + h->root.u.def.section->output_section->vma
579 + h->root.u.def.section->output_offset);
580 }
581
582 switch (r_type)
583 {
584 case R_FT32_8:
585 case R_FT32_10:
586 case R_FT32_16:
587 case R_FT32_20:
588 case R_FT32_RELAX:
589 if (symval != 0)
590 return FALSE;
591 insn = bfd_get_32 (abfd, contents + irel->r_offset);
592 insn |= ((symval + irel->r_addend) << howto->bitpos) & howto->dst_mask;
593 return ft32_shortcode (insn, sc);
594
595 case R_FT32_18:
596 insn = bfd_get_32 (abfd, contents + irel->r_offset);
597 /* Get the address of this instruction. */
598 dot = (sec->output_section->vma
599 + sec->output_offset + irel->r_offset);
600 value = symval + irel->r_addend;
601 offset = (value - dot) / 4;
602
603 if ((dot > 0x8c) && (-256 <= offset) && (offset < 256))
604 {
605 switch (insn)
606 {
607 case 0x00200000: *sc = (3 << 13) | (0 << 9); return TRUE;
608 case 0x00280000: *sc = (3 << 13) | (1 << 9); return TRUE;
609 case 0x00600000: *sc = (3 << 13) | (2 << 9); return TRUE;
610 case 0x00680000: *sc = (3 << 13) | (3 << 9); return TRUE;
611 case 0x00a00000: *sc = (3 << 13) | (4 << 9); return TRUE;
612 case 0x00a80000: *sc = (3 << 13) | (5 << 9); return TRUE;
613 case 0x00e00000: *sc = (3 << 13) | (6 << 9); return TRUE;
614 case 0x00e80000: *sc = (3 << 13) | (7 << 9); return TRUE;
615 case 0x01200000: *sc = (3 << 13) | (8 << 9); return TRUE;
616 case 0x01280000: *sc = (3 << 13) | (9 << 9); return TRUE;
617 case 0x01600000: *sc = (3 << 13) | (10 << 9); return TRUE;
618 case 0x01680000: *sc = (3 << 13) | (11 << 9); return TRUE;
619 case 0x01a00000: *sc = (3 << 13) | (12 << 9); return TRUE;
620 case 0x01a80000: *sc = (3 << 13) | (13 << 9); return TRUE;
621
622 case 0x00300000: *sc = (3 << 13) | (14 << 9); return TRUE;
623 case 0x00340000: *sc = (3 << 13) | (15 << 9); return TRUE;
624
625 default:
626 break;
627 }
628 }
629 break;
630
631 default:
632 break;
633 }
634 return FALSE;
635 }
636
637 /* Returns whether the relocation type passed is a diff reloc. */
638
639 static bfd_boolean
640 elf32_ft32_is_diff_reloc (Elf_Internal_Rela *irel)
641 {
642 return (ELF32_R_TYPE (irel->r_info) == R_FT32_DIFF32);
643 }
644
645 /* Reduce the diff value written in the section by count if the shrinked
646 insn address happens to fall between the two symbols for which this
647 diff reloc was emitted. */
648
649 static bfd_boolean
650 elf32_ft32_adjust_diff_reloc_value (bfd *abfd,
651 struct bfd_section *isec,
652 Elf_Internal_Rela *irel,
653 bfd_vma symval,
654 bfd_vma shrinked_insn_address,
655 int count)
656 {
657 unsigned char * reloc_contents = NULL;
658 unsigned char * isec_contents = elf_section_data (isec)->this_hdr.contents;
659 bfd_signed_vma x = 0;
660 bfd_vma sym2_address;
661 bfd_vma sym1_address;
662 bfd_vma start_address;
663 bfd_vma end_address;
664
665
666 if (isec_contents == NULL)
667 {
668 if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
669 return FALSE;
670
671 elf_section_data (isec)->this_hdr.contents = isec_contents;
672 }
673
674 reloc_contents = isec_contents + irel->r_offset;
675
676 /* Read value written in object file. */
677 switch (ELF32_R_TYPE (irel->r_info))
678 {
679 case R_FT32_DIFF32:
680 x = bfd_get_signed_32 (abfd, reloc_contents);
681 break;
682
683 default:
684 return FALSE;
685 }
686
687 /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
688 into the object file at the reloc offset. sym2's logical value is
689 symval (<start_of_section>) + reloc addend. Compute the start and end
690 addresses and check if the shrinked insn falls between sym1 and sym2. */
691 sym2_address = symval + irel->r_addend;
692 sym1_address = sym2_address - x;
693
694 /* Don't assume sym2 is bigger than sym1 - the difference
695 could be negative. Compute start and end addresses, and
696 use those to see if they span shrinked_insn_address. */
697 start_address = sym1_address < sym2_address ? sym1_address : sym2_address;
698 end_address = sym1_address > sym2_address ? sym1_address : sym2_address;
699
700 if (shrinked_insn_address >= start_address
701 && shrinked_insn_address < end_address)
702 {
703 /* Reduce the diff value by count bytes and write it back into section
704 contents. */
705 bfd_signed_vma new_diff = x < 0 ? x + count : x - count;
706
707 if (sym2_address > shrinked_insn_address)
708 irel->r_addend -= count;
709
710 switch (ELF32_R_TYPE (irel->r_info))
711 {
712 case R_FT32_DIFF32:
713 bfd_put_signed_32 (abfd, new_diff & 0xFFFFFFFF, reloc_contents);
714 break;
715
716 default:
717 return FALSE;
718 }
719 }
720
721 return TRUE;
722 }
723
724 static bfd_boolean
725 elf32_ft32_adjust_reloc_if_spans_insn (bfd *abfd,
726 asection *isec,
727 Elf_Internal_Rela *irel, bfd_vma symval,
728 bfd_vma shrinked_insn_address,
729 bfd_vma shrink_boundary,
730 int count)
731 {
732
733 if (elf32_ft32_is_diff_reloc (irel))
734 {
735 if (!elf32_ft32_adjust_diff_reloc_value (abfd, isec, irel,
736 symval,
737 shrinked_insn_address,
738 count))
739 return FALSE;
740 }
741 else
742 {
743 bfd_vma reloc_value = symval + irel->r_addend;
744 bfd_boolean addend_within_shrink_boundary =
745 (reloc_value <= shrink_boundary);
746 bfd_boolean reloc_spans_insn =
747 (symval <= shrinked_insn_address
748 && reloc_value > shrinked_insn_address
749 && addend_within_shrink_boundary);
750
751 if (! reloc_spans_insn)
752 return TRUE;
753
754 irel->r_addend -= count;
755
756 if (debug_relax)
757 printf ("Relocation's addend needed to be fixed \n");
758 }
759 return TRUE;
760 }
761
762 /* Delete some bytes from a section while relaxing. */
763
764 static bfd_boolean
765 elf32_ft32_relax_delete_bytes (struct bfd_link_info *link_info, bfd * abfd,
766 asection * sec, bfd_vma addr, int count)
767 {
768 Elf_Internal_Shdr *symtab_hdr;
769 unsigned int sec_shndx;
770 bfd_byte *contents;
771 Elf_Internal_Rela *irel, *irelend;
772 bfd_vma toaddr;
773 Elf_Internal_Sym *isym;
774 Elf_Internal_Sym *isymend;
775 struct elf_link_hash_entry **sym_hashes;
776 struct elf_link_hash_entry **end_hashes;
777 struct elf_link_hash_entry **start_hashes;
778 unsigned int symcount;
779 Elf_Internal_Sym *isymbuf = NULL;
780
781 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
782 sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
783
784 contents = elf_section_data (sec)->this_hdr.contents;
785
786 toaddr = sec->size;
787
788 irel = elf_section_data (sec)->relocs;
789 irelend = irel + sec->reloc_count;
790
791 /* Actually delete the bytes. */
792 memmove (contents + addr, contents + addr + count,
793 (size_t) (toaddr - addr - count));
794 sec->size -= count;
795
796 /* Adjust all the relocs. */
797 for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
798 /* Get the new reloc address. */
799 if ((irel->r_offset > addr && irel->r_offset < toaddr))
800 irel->r_offset -= count;
801
802 /* The reloc's own addresses are now ok. However, we need to readjust
803 the reloc's addend, i.e. the reloc's value if two conditions are met:
804 1.) the reloc is relative to a symbol in this section that
805 is located in front of the shrinked instruction
806 2.) symbol plus addend end up behind the shrinked instruction.
807
808 The most common case where this happens are relocs relative to
809 the section-start symbol.
810
811 This step needs to be done for all of the sections of the bfd. */
812 {
813 struct bfd_section *isec;
814
815 for (isec = abfd->sections; isec; isec = isec->next)
816 {
817 bfd_vma symval;
818 bfd_vma shrinked_insn_address;
819
820 if (isec->reloc_count == 0)
821 continue;
822
823 shrinked_insn_address = (sec->output_section->vma
824 + sec->output_offset + addr - count);
825
826 irel = elf_section_data (isec)->relocs;
827 /* PR 12161: Read in the relocs for this section if necessary. */
828 if (irel == NULL)
829 irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
830
831 for (irelend = irel + isec->reloc_count; irel < irelend; irel++)
832 {
833 /* Read this BFD's local symbols if we haven't done
834 so already. */
835 if (isymbuf == NULL && symtab_hdr->sh_info != 0)
836 {
837 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
838 if (isymbuf == NULL)
839 isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
840 symtab_hdr->sh_info, 0,
841 NULL, NULL, NULL);
842 if (isymbuf == NULL)
843 return FALSE;
844 }
845
846 /* Get the value of the symbol referred to by the reloc. */
847 if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
848 {
849 /* A local symbol. */
850 asection *sym_sec;
851
852 isym = isymbuf + ELF32_R_SYM (irel->r_info);
853 sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
854 symval = isym->st_value;
855 /* If the reloc is absolute, it will not have
856 a symbol or section associated with it. */
857 if (sym_sec == sec)
858 {
859 symval += sym_sec->output_section->vma
860 + sym_sec->output_offset;
861
862 if (debug_relax)
863 printf ("Checking if the relocation's "
864 "addend needs corrections.\n"
865 "Address of anchor symbol: 0x%x \n"
866 "Address of relocation target: 0x%x \n"
867 "Address of relaxed insn: 0x%x \n",
868 (unsigned int) symval,
869 (unsigned int) (symval + irel->r_addend),
870 (unsigned int) shrinked_insn_address);
871
872 if (symval <= shrinked_insn_address
873 && (symval + irel->r_addend) > shrinked_insn_address)
874 {
875 /* If there is an alignment boundary, we only need to
876 adjust addends that end up below the boundary. */
877 bfd_vma shrink_boundary = (toaddr
878 + sec->output_section->vma
879 + sec->output_offset);
880
881 if (debug_relax)
882 printf
883 ("Relocation's addend needed to be fixed \n");
884
885 if (!elf32_ft32_adjust_reloc_if_spans_insn (abfd, isec,
886 irel, symval,
887 shrinked_insn_address,
888 shrink_boundary,
889 count))
890 return FALSE;
891 }
892 }
893 /* else reference symbol is absolute. No adjustment needed. */
894 }
895 /* else...Reference symbol is extern. No need for adjusting
896 the addend. */
897 }
898 }
899 }
900
901 /* Adjust the local symbols defined in this section. */
902 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
903 isym = (Elf_Internal_Sym *) symtab_hdr->contents;
904 if (isym)
905 {
906 for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
907 {
908 if (isym->st_shndx == sec_shndx
909 && isym->st_value > addr && isym->st_value < toaddr)
910 isym->st_value -= count;
911 }
912 }
913
914 /* Now adjust the global symbols defined in this section. */
915 symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
916 - symtab_hdr->sh_info);
917 sym_hashes = start_hashes = elf_sym_hashes (abfd);
918 end_hashes = sym_hashes + symcount;
919
920 for (; sym_hashes < end_hashes; sym_hashes++)
921 {
922 struct elf_link_hash_entry *sym_hash = *sym_hashes;
923
924 /* The '--wrap SYMBOL' option is causing a pain when the object file,
925 containing the definition of __wrap_SYMBOL, includes a direct
926 call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference
927 the same symbol (which is __wrap_SYMBOL), but still exist as two
928 different symbols in 'sym_hashes', we don't want to adjust
929 the global symbol __wrap_SYMBOL twice.
930 This check is only relevant when symbols are being wrapped. */
931 if (link_info->wrap_hash != NULL)
932 {
933 struct elf_link_hash_entry **cur_sym_hashes;
934
935 /* Loop only over the symbols whom been already checked. */
936 for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes;
937 cur_sym_hashes++)
938 /* If the current symbol is identical to 'sym_hash', that means
939 the symbol was already adjusted (or at least checked). */
940 if (*cur_sym_hashes == sym_hash)
941 break;
942
943 /* Don't adjust the symbol again. */
944 if (cur_sym_hashes < sym_hashes)
945 continue;
946 }
947
948 if ((sym_hash->root.type == bfd_link_hash_defined
949 || sym_hash->root.type == bfd_link_hash_defweak)
950 && sym_hash->root.u.def.section == sec
951 && sym_hash->root.u.def.value > addr
952 && sym_hash->root.u.def.value < toaddr)
953 sym_hash->root.u.def.value -= count;
954 }
955
956 return TRUE;
957 }
958
959 /* Return TRUE if LOC can be a target of a branch, jump or call. */
960
961 static bfd_boolean
962 elf32_ft32_relax_is_branch_target (struct bfd_link_info *link_info,
963 bfd * abfd, asection * sec,
964 bfd_vma loc)
965 {
966 Elf_Internal_Shdr *symtab_hdr;
967 Elf_Internal_Rela *irel, *irelend;
968 Elf_Internal_Sym *isym;
969 Elf_Internal_Sym *isymbuf = NULL;
970 bfd_vma symval;
971 struct bfd_section *isec;
972
973 struct elf_link_hash_entry **sym_hashes;
974 struct elf_link_hash_entry **end_hashes;
975 struct elf_link_hash_entry **start_hashes;
976 unsigned int symcount;
977
978 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
979
980 /* Now we check for relocations pointing to ret. */
981 for (isec = abfd->sections; isec; isec = isec->next)
982 {
983 irel = elf_section_data (isec)->relocs;
984 if (irel == NULL)
985 irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
986
987 irelend = irel + isec->reloc_count;
988
989 for (; irel < irelend; irel++)
990 {
991 /* Read this BFD's local symbols if we haven't done
992 so already. */
993 if (isymbuf == NULL && symtab_hdr->sh_info != 0)
994 {
995 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
996 if (isymbuf == NULL)
997 isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
998 symtab_hdr->sh_info, 0,
999 NULL, NULL, NULL);
1000 if (isymbuf == NULL)
1001 return FALSE;
1002 }
1003
1004 /* Get the value of the symbol referred to by the reloc. */
1005 if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1006 {
1007 /* A local symbol. */
1008 asection *sym_sec;
1009
1010 isym = isymbuf + ELF32_R_SYM (irel->r_info);
1011 sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1012 symval = isym->st_value;
1013 /* If the reloc is absolute, it will not have
1014 a symbol or section associated with it. */
1015 if (sym_sec == sec)
1016 {
1017 symval += sym_sec->output_section->vma
1018 + sym_sec->output_offset;
1019
1020 if (debug_relax)
1021 printf ("0x%x: Address of anchor symbol: 0x%x "
1022 "Address of relocation target: 0x%x \n",
1023 (unsigned int) irel->r_offset,
1024 (unsigned int) symval,
1025 (unsigned int) (symval + irel->r_addend));
1026 if ((irel->r_addend) == loc)
1027 return TRUE;
1028 }
1029 }
1030 }
1031 }
1032
1033 symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
1034 - symtab_hdr->sh_info);
1035 sym_hashes = start_hashes = elf_sym_hashes (abfd);
1036 end_hashes = sym_hashes + symcount;
1037
1038 for (; sym_hashes < end_hashes; sym_hashes++)
1039 {
1040 struct elf_link_hash_entry *sym_hash = *sym_hashes;
1041
1042 /* The '--wrap SYMBOL' option is causing a pain when the object file,
1043 containing the definition of __wrap_SYMBOL, includes a direct
1044 call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference
1045 the same symbol (which is __wrap_SYMBOL), but still exist as two
1046 different symbols in 'sym_hashes', we don't want to adjust
1047 the global symbol __wrap_SYMBOL twice.
1048 This check is only relevant when symbols are being wrapped. */
1049 if (link_info->wrap_hash != NULL)
1050 {
1051 struct elf_link_hash_entry **cur_sym_hashes;
1052
1053 /* Loop only over the symbols whom been already checked. */
1054 for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes;
1055 cur_sym_hashes++)
1056 /* If the current symbol is identical to 'sym_hash', that means
1057 the symbol was already adjusted (or at least checked). */
1058 if (*cur_sym_hashes == sym_hash)
1059 break;
1060
1061 /* Don't adjust the symbol again. */
1062 if (cur_sym_hashes < sym_hashes)
1063 continue;
1064 }
1065
1066 if ((sym_hash->root.type == bfd_link_hash_defined
1067 || sym_hash->root.type == bfd_link_hash_defweak)
1068 && sym_hash->root.u.def.section == sec
1069 && sym_hash->root.u.def.value == loc)
1070 return TRUE;
1071 }
1072
1073 return FALSE;
1074 }
1075
1076 static bfd_boolean
1077 ft32_elf_relax_section
1078 (bfd * abfd,
1079 asection * sec,
1080 struct bfd_link_info * link_info,
1081 bfd_boolean * again)
1082 {
1083 Elf_Internal_Rela * free_relocs = NULL;
1084 Elf_Internal_Rela * internal_relocs;
1085 Elf_Internal_Rela * irelend;
1086 Elf_Internal_Rela * irel;
1087 bfd_byte * contents = NULL;
1088 Elf_Internal_Shdr * symtab_hdr;
1089 Elf_Internal_Sym * isymbuf = NULL;
1090
1091 /* Assume nothing changes. */
1092 *again = FALSE;
1093
1094 /* We don't have to do anything for a relocatable link, if
1095 this section does not have relocs, or if this is not a
1096 code section. */
1097 if (bfd_link_relocatable (link_info)
1098 || (sec->flags & SEC_RELOC) == 0
1099 || sec->reloc_count == 0
1100 || (sec->flags & SEC_CODE) == 0)
1101 return TRUE;
1102
1103 /* Get the section contents. */
1104 if (elf_section_data (sec)->this_hdr.contents != NULL)
1105 contents = elf_section_data (sec)->this_hdr.contents;
1106 /* Go get them off disk. */
1107 else
1108 {
1109 if (! bfd_malloc_and_get_section (abfd, sec, &contents))
1110 goto error_return;
1111 elf_section_data (sec)->this_hdr.contents = contents;
1112 }
1113
1114 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1115
1116 /* Read this BFD's local symbols if we haven't done so already. */
1117 if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1118 {
1119 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1120 if (isymbuf == NULL)
1121 isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1122 symtab_hdr->sh_info, 0,
1123 NULL, NULL, NULL);
1124 if (isymbuf == NULL)
1125 goto error_return;
1126 symtab_hdr->contents = (unsigned char *) isymbuf;
1127 }
1128
1129 internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
1130 link_info->keep_memory);
1131 if (internal_relocs == NULL)
1132 goto error_return;
1133 if (! link_info->keep_memory)
1134 free_relocs = internal_relocs;
1135
1136 /* Walk through them looking for relaxing opportunities. */
1137 irelend = internal_relocs + sec->reloc_count;
1138
1139 /* Test every adjacent pair of relocs. If both have shortcodes,
1140 fuse them and delete the relocs. */
1141 irel = internal_relocs;
1142 while (irel < irelend - 1)
1143 {
1144 Elf_Internal_Rela * irel_next = irel + 1;
1145 unsigned int sc0, sc1;
1146 bfd_vma pc;
1147
1148 pc = irel->r_offset;
1149
1150 if (((pc + 4) == (irel_next->r_offset))
1151 && ft32_reloc_shortable (abfd, sec, isymbuf, contents, pc, irel,
1152 &sc0)
1153 && ft32_reloc_shortable (abfd, sec, isymbuf, contents, pc,
1154 irel_next, &sc1)
1155 && !elf32_ft32_relax_is_branch_target (link_info, abfd, sec,
1156 irel_next->r_offset))
1157 {
1158 unsigned int code30 = (sc1 << 15) | sc0;
1159 unsigned int code27 = code30 >> 3;
1160 unsigned int code3 = code30 & 7;
1161 static const unsigned char pat3[] = {2, 3, 4, 5, 6, 9, 10, 14};
1162 unsigned int pattern = pat3[code3];
1163 unsigned int fused = (pattern << 27) | code27;
1164
1165 /* Move second reloc to same place as first. */
1166 irel_next->r_offset = irel->r_offset;
1167
1168 /* Change both relocs to R_FT32_NONE. */
1169
1170 if (ELF32_R_TYPE (irel->r_info) == R_FT32_18)
1171 {
1172 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1173 R_FT32_SC0);
1174 }
1175 else
1176 {
1177 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1178 R_FT32_NONE);
1179 }
1180
1181 if (ELF32_R_TYPE (irel_next->r_info) == R_FT32_18)
1182 {
1183 irel_next->r_info = ELF32_R_INFO (ELF32_R_SYM (irel_next->r_info),
1184 R_FT32_SC1);
1185 }
1186 else
1187 {
1188 irel_next->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1189 R_FT32_NONE);
1190 }
1191
1192 /* Replace the first insn with the fused version. */
1193 bfd_put_32 (abfd, fused, contents + irel->r_offset);
1194
1195 /* Delete the second insn. */
1196 if (!elf32_ft32_relax_delete_bytes (link_info, abfd, sec,
1197 irel->r_offset + 4, 4))
1198 goto error_return;
1199
1200 /* That will change things, so, we should relax again.
1201 Note that this is not required, and it may be slow. */
1202 *again = TRUE;
1203
1204 irel += 2;
1205 }
1206 else
1207 {
1208 irel += 1;
1209 }
1210 }
1211
1212 if (isymbuf != NULL
1213 && symtab_hdr->contents != (unsigned char *) isymbuf)
1214 {
1215 if (! link_info->keep_memory)
1216 free (isymbuf);
1217 else
1218 /* Cache the symbols for elf_link_input_bfd. */
1219 symtab_hdr->contents = (unsigned char *) isymbuf;
1220 }
1221
1222 if (contents != NULL
1223 && elf_section_data (sec)->this_hdr.contents != contents)
1224 {
1225 if (! link_info->keep_memory)
1226 free (contents);
1227 else
1228 /* Cache the section contents for elf_link_input_bfd. */
1229 elf_section_data (sec)->this_hdr.contents = contents;
1230
1231 }
1232
1233 if (internal_relocs != NULL
1234 && elf_section_data (sec)->relocs != internal_relocs)
1235 free (internal_relocs);
1236
1237 return TRUE;
1238
1239 error_return:
1240 if (free_relocs != NULL)
1241 free (free_relocs);
1242
1243 return TRUE;
1244 }
1245 \f
1246 #define ELF_ARCH bfd_arch_ft32
1247 #define ELF_MACHINE_CODE EM_FT32
1248 #define ELF_MAXPAGESIZE 0x1
1249
1250 #define TARGET_LITTLE_SYM ft32_elf32_vec
1251 #define TARGET_LITTLE_NAME "elf32-ft32"
1252
1253 #define elf_info_to_howto_rel NULL
1254 #define elf_info_to_howto ft32_info_to_howto_rela
1255 #define elf_backend_relocate_section ft32_elf_relocate_section
1256
1257 #define elf_backend_can_gc_sections 1
1258 #define elf_backend_rela_normal 1
1259
1260 #define bfd_elf32_bfd_reloc_type_lookup ft32_reloc_type_lookup
1261 #define bfd_elf32_bfd_reloc_name_lookup ft32_reloc_name_lookup
1262
1263 #define bfd_elf32_bfd_relax_section ft32_elf_relax_section
1264
1265 #include "elf32-target.h"
This page took 0.057955 seconds and 5 git commands to generate.