FT32B is a new FT32 family member. It has a code compression scheme, which requires...
[deliverable/binutils-gdb.git] / bfd / elf32-ft32.c
1 /* ft32-specific support for 32-bit ELF.
2 Copyright (C) 2013-2017 Free Software Foundation, Inc.
3
4 Copied from elf32-moxie.c which is..
5 Copyright (C) 2009-2017 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 void
296 ft32_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
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 BFD_ASSERT (r_type < (unsigned int) R_FT32_max);
304 cache_ptr->howto = & ft32_elf_howto_table [r_type];
305 }
306
307 /* Relocate an FT32 ELF section.
308
309 The RELOCATE_SECTION function is called by the new ELF backend linker
310 to handle the relocations for a section.
311
312 The relocs are always passed as Rela structures; if the section
313 actually uses Rel structures, the r_addend field will always be
314 zero.
315
316 This function is responsible for adjusting the section contents as
317 necessary, and (if using Rela relocs and generating a relocatable
318 output file) adjusting the reloc addend as necessary.
319
320 This function does not have to worry about setting the reloc
321 address or the reloc symbol index.
322
323 LOCAL_SYMS is a pointer to the swapped in local symbols.
324
325 LOCAL_SECTIONS is an array giving the section in the input file
326 corresponding to the st_shndx field of each local symbol.
327
328 The global hash table entry for the global symbols can be found
329 via elf_sym_hashes (input_bfd).
330
331 When generating relocatable output, this function must handle
332 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
333 going to be the section symbol corresponding to the output
334 section, which means that the addend must be adjusted
335 accordingly. */
336
337 static bfd_boolean
338 ft32_elf_relocate_section (bfd *output_bfd,
339 struct bfd_link_info *info,
340 bfd *input_bfd,
341 asection *input_section,
342 bfd_byte *contents,
343 Elf_Internal_Rela *relocs,
344 Elf_Internal_Sym *local_syms,
345 asection **local_sections)
346 {
347 Elf_Internal_Shdr *symtab_hdr;
348 struct elf_link_hash_entry **sym_hashes;
349 Elf_Internal_Rela *rel;
350 Elf_Internal_Rela *relend;
351
352 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
353 sym_hashes = elf_sym_hashes (input_bfd);
354 relend = relocs + input_section->reloc_count;
355
356 for (rel = relocs; rel < relend; rel ++)
357 {
358 reloc_howto_type *howto;
359 unsigned long r_symndx;
360 Elf_Internal_Sym *sym;
361 asection *sec;
362 struct elf_link_hash_entry *h;
363 bfd_vma relocation;
364 bfd_reloc_status_type r;
365 const char *name;
366 int r_type;
367
368 r_type = ELF32_R_TYPE (rel->r_info);
369 r_symndx = ELF32_R_SYM (rel->r_info);
370 howto = ft32_elf_howto_table + r_type;
371 h = NULL;
372 sym = NULL;
373 sec = NULL;
374
375 if (r_symndx < symtab_hdr->sh_info)
376 {
377 sym = local_syms + r_symndx;
378 sec = local_sections [r_symndx];
379 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
380
381 name = bfd_elf_string_from_elf_section
382 (input_bfd, symtab_hdr->sh_link, sym->st_name);
383 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
384 }
385 else
386 {
387 bfd_boolean unresolved_reloc, warned, ignored;
388
389 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
390 r_symndx, symtab_hdr, sym_hashes,
391 h, sec, relocation,
392 unresolved_reloc, warned, ignored);
393
394 name = h->root.root.string;
395 }
396
397 if (sec != NULL && discarded_section (sec))
398 RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
399 rel, 1, relend, howto, 0, contents);
400
401 if (bfd_link_relocatable (info))
402 continue;
403
404 switch (howto->type)
405 {
406 case R_FT32_SC0:
407 {
408 unsigned int insn;
409 int offset;
410 unsigned int code15[2];
411
412 insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
413 ft32_split_shortcode (insn, code15);
414
415 offset = (int)relocation;
416 offset += (int)(rel->r_addend - rel->r_offset);
417 offset -= (input_section->output_section->vma +
418 input_section->output_offset);
419 if ((offset < -1024) || (offset >= 1024))
420 {
421 r = bfd_reloc_outofrange;
422 break;
423 }
424 code15[0] |= ((offset / 4) & 511);
425 insn = ft32_merge_shortcode (code15);
426 bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
427 }
428 r = bfd_reloc_ok;
429 break;
430
431 case R_FT32_SC1:
432 {
433 unsigned int insn;
434 int offset;
435 unsigned int code15[2];
436
437 insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
438 ft32_split_shortcode (insn, code15);
439
440 offset = (int)relocation;
441 offset += (int)(rel->r_addend - rel->r_offset);
442 offset -= (input_section->output_section->vma +
443 input_section->output_offset);
444 if ((offset < -1024) || (offset >= 1024))
445 {
446 r = bfd_reloc_outofrange;
447 break;
448 }
449 code15[1] |= ((offset / 4) & 511);
450 insn = ft32_merge_shortcode (code15);
451 bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
452 }
453 r = bfd_reloc_ok;
454 break;
455
456 case R_FT32_DIFF32:
457 r = bfd_reloc_ok;
458 break;
459
460 default:
461 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
462 contents, rel->r_offset,
463 relocation, rel->r_addend);
464 break;
465 }
466
467 if (r != bfd_reloc_ok)
468 {
469 const char * msg = NULL;
470
471 switch (r)
472 {
473 case bfd_reloc_overflow:
474 (*info->callbacks->reloc_overflow)
475 (info, (h ? &h->root : NULL), name, howto->name,
476 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
477 break;
478
479 case bfd_reloc_undefined:
480 (*info->callbacks->undefined_symbol)
481 (info, name, input_bfd, input_section, rel->r_offset, TRUE);
482 break;
483
484 case bfd_reloc_outofrange:
485 msg = _("internal error: out of range error");
486 break;
487
488 case bfd_reloc_notsupported:
489 msg = _("internal error: unsupported relocation error");
490 break;
491
492 case bfd_reloc_dangerous:
493 msg = _("internal error: dangerous relocation");
494 break;
495
496 default:
497 msg = _("internal error: unknown error");
498 break;
499 }
500
501 if (msg)
502 (*info->callbacks->warning) (info, msg, name, input_bfd,
503 input_section, rel->r_offset);
504 }
505 }
506
507 return TRUE;
508 }
509 \f
510 /* Relaxation. */
511
512 static bfd_boolean
513 ft32_reloc_shortable
514 (bfd * abfd,
515 asection * sec,
516 Elf_Internal_Sym * isymbuf ATTRIBUTE_UNUSED,
517 bfd_byte * contents,
518 bfd_vma pc ATTRIBUTE_UNUSED,
519 Elf_Internal_Rela * irel,
520 unsigned int * sc)
521 {
522 Elf_Internal_Shdr *symtab_hdr ATTRIBUTE_UNUSED;
523 bfd_vma symval;
524
525 enum elf_ft32_reloc_type r_type;
526 reloc_howto_type *howto = NULL;
527 unsigned int insn;
528 int offset;
529 bfd_vma dot, value;
530
531 r_type = ELF32_R_TYPE (irel->r_info);
532 howto = &ft32_elf_howto_table [r_type];
533
534 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
535
536 /* Get the value of the symbol referred to by the reloc. */
537 if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
538 {
539 /* A local symbol. */
540 Elf_Internal_Sym *isym;
541 asection *sym_sec;
542
543 isym = isymbuf + ELF32_R_SYM (irel->r_info);
544 sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
545 symval = isym->st_value;
546 /* If the reloc is absolute, it will not have
547 a symbol or section associated with it. */
548 if (sym_sec)
549 symval += sym_sec->output_section->vma
550 + sym_sec->output_offset;
551 }
552 else
553 {
554 unsigned long indx;
555 struct elf_link_hash_entry *h;
556
557 /* An external symbol. */
558 indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
559 h = elf_sym_hashes (abfd)[indx];
560 BFD_ASSERT (h != NULL);
561 if (h->root.type != bfd_link_hash_defined
562 && h->root.type != bfd_link_hash_defweak)
563 /* This appears to be a reference to an undefined
564 symbol. Just ignore it--it will be caught by the
565 regular reloc processing. */
566 return FALSE;
567
568 symval = (h->root.u.def.value
569 + h->root.u.def.section->output_section->vma
570 + h->root.u.def.section->output_offset);
571 }
572
573 switch (r_type)
574 {
575 case R_FT32_8:
576 case R_FT32_10:
577 case R_FT32_16:
578 case R_FT32_20:
579 case R_FT32_RELAX:
580 if (symval != 0)
581 return FALSE;
582 insn = bfd_get_32 (abfd, contents + irel->r_offset);
583 insn |= ((symval + irel->r_addend) << howto->bitpos) & howto->dst_mask;
584 return ft32_shortcode (insn, sc);
585
586 case R_FT32_18:
587 insn = bfd_get_32 (abfd, contents + irel->r_offset);
588 /* Get the address of this instruction. */
589 dot = (sec->output_section->vma
590 + sec->output_offset + irel->r_offset);
591 value = symval + irel->r_addend;
592 offset = (value - dot) / 4;
593
594 if ((dot > 0x8c) && (-256 <= offset) && (offset < 256))
595 {
596 switch (insn)
597 {
598 case 0x00200000: *sc = (3 << 13) | (0 << 9); return TRUE;
599 case 0x00280000: *sc = (3 << 13) | (1 << 9); return TRUE;
600 case 0x00600000: *sc = (3 << 13) | (2 << 9); return TRUE;
601 case 0x00680000: *sc = (3 << 13) | (3 << 9); return TRUE;
602 case 0x00a00000: *sc = (3 << 13) | (4 << 9); return TRUE;
603 case 0x00a80000: *sc = (3 << 13) | (5 << 9); return TRUE;
604 case 0x00e00000: *sc = (3 << 13) | (6 << 9); return TRUE;
605 case 0x00e80000: *sc = (3 << 13) | (7 << 9); return TRUE;
606 case 0x01200000: *sc = (3 << 13) | (8 << 9); return TRUE;
607 case 0x01280000: *sc = (3 << 13) | (9 << 9); return TRUE;
608 case 0x01600000: *sc = (3 << 13) | (10 << 9); return TRUE;
609 case 0x01680000: *sc = (3 << 13) | (11 << 9); return TRUE;
610 case 0x01a00000: *sc = (3 << 13) | (12 << 9); return TRUE;
611 case 0x01a80000: *sc = (3 << 13) | (13 << 9); return TRUE;
612
613 case 0x00300000: *sc = (3 << 13) | (14 << 9); return TRUE;
614 case 0x00340000: *sc = (3 << 13) | (15 << 9); return TRUE;
615
616 default:
617 break;
618 }
619 }
620 break;
621
622 default:
623 break;
624 }
625 return FALSE;
626 }
627
628 /* Returns whether the relocation type passed is a diff reloc. */
629
630 static bfd_boolean
631 elf32_ft32_is_diff_reloc (Elf_Internal_Rela *irel)
632 {
633 return (ELF32_R_TYPE (irel->r_info) == R_FT32_DIFF32);
634 }
635
636 /* Reduce the diff value written in the section by count if the shrinked
637 insn address happens to fall between the two symbols for which this
638 diff reloc was emitted. */
639
640 static bfd_boolean
641 elf32_ft32_adjust_diff_reloc_value (bfd *abfd,
642 struct bfd_section *isec,
643 Elf_Internal_Rela *irel,
644 bfd_vma symval,
645 bfd_vma shrinked_insn_address,
646 int count)
647 {
648 unsigned char * reloc_contents = NULL;
649 unsigned char * isec_contents = elf_section_data (isec)->this_hdr.contents;
650 bfd_signed_vma x = 0;
651 bfd_vma sym2_address;
652 bfd_vma sym1_address;
653 bfd_vma start_address;
654 bfd_vma end_address;
655
656
657 if (isec_contents == NULL)
658 {
659 if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
660 return FALSE;
661
662 elf_section_data (isec)->this_hdr.contents = isec_contents;
663 }
664
665 reloc_contents = isec_contents + irel->r_offset;
666
667 /* Read value written in object file. */
668 switch (ELF32_R_TYPE (irel->r_info))
669 {
670 case R_FT32_DIFF32:
671 x = bfd_get_signed_32 (abfd, reloc_contents);
672 break;
673
674 default:
675 return FALSE;
676 }
677
678 /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
679 into the object file at the reloc offset. sym2's logical value is
680 symval (<start_of_section>) + reloc addend. Compute the start and end
681 addresses and check if the shrinked insn falls between sym1 and sym2. */
682 sym2_address = symval + irel->r_addend;
683 sym1_address = sym2_address - x;
684
685 /* Don't assume sym2 is bigger than sym1 - the difference
686 could be negative. Compute start and end addresses, and
687 use those to see if they span shrinked_insn_address. */
688 start_address = sym1_address < sym2_address ? sym1_address : sym2_address;
689 end_address = sym1_address > sym2_address ? sym1_address : sym2_address;
690
691 if (shrinked_insn_address >= start_address
692 && shrinked_insn_address < end_address)
693 {
694 /* Reduce the diff value by count bytes and write it back into section
695 contents. */
696 bfd_signed_vma new_diff = x < 0 ? x + count : x - count;
697
698 if (sym2_address > shrinked_insn_address)
699 irel->r_addend -= count;
700
701 switch (ELF32_R_TYPE (irel->r_info))
702 {
703 case R_FT32_DIFF32:
704 bfd_put_signed_32 (abfd, new_diff & 0xFFFFFFFF, reloc_contents);
705 break;
706
707 default:
708 return FALSE;
709 }
710 }
711
712 return TRUE;
713 }
714
715 static bfd_boolean
716 elf32_ft32_adjust_reloc_if_spans_insn (bfd *abfd,
717 asection *isec,
718 Elf_Internal_Rela *irel, bfd_vma symval,
719 bfd_vma shrinked_insn_address,
720 bfd_vma shrink_boundary,
721 int count)
722 {
723
724 if (elf32_ft32_is_diff_reloc (irel))
725 {
726 if (!elf32_ft32_adjust_diff_reloc_value (abfd, isec, irel,
727 symval,
728 shrinked_insn_address,
729 count))
730 return FALSE;
731 }
732 else
733 {
734 bfd_vma reloc_value = symval + irel->r_addend;
735 bfd_boolean addend_within_shrink_boundary =
736 (reloc_value <= shrink_boundary);
737 bfd_boolean reloc_spans_insn =
738 (symval <= shrinked_insn_address
739 && reloc_value > shrinked_insn_address
740 && addend_within_shrink_boundary);
741
742 if (! reloc_spans_insn)
743 return TRUE;
744
745 irel->r_addend -= count;
746
747 if (debug_relax)
748 printf ("Relocation's addend needed to be fixed \n");
749 }
750 return TRUE;
751 }
752
753 /* Delete some bytes from a section while relaxing. */
754
755 static bfd_boolean
756 elf32_ft32_relax_delete_bytes (struct bfd_link_info *link_info, bfd * abfd,
757 asection * sec, bfd_vma addr, int count)
758 {
759 Elf_Internal_Shdr *symtab_hdr;
760 unsigned int sec_shndx;
761 bfd_byte *contents;
762 Elf_Internal_Rela *irel, *irelend;
763 bfd_vma toaddr;
764 Elf_Internal_Sym *isym;
765 Elf_Internal_Sym *isymend;
766 struct elf_link_hash_entry **sym_hashes;
767 struct elf_link_hash_entry **end_hashes;
768 struct elf_link_hash_entry **start_hashes;
769 unsigned int symcount;
770 Elf_Internal_Sym *isymbuf = NULL;
771
772 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
773 sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
774
775 contents = elf_section_data (sec)->this_hdr.contents;
776
777 toaddr = sec->size;
778
779 irel = elf_section_data (sec)->relocs;
780 irelend = irel + sec->reloc_count;
781
782 /* Actually delete the bytes. */
783 memmove (contents + addr, contents + addr + count,
784 (size_t) (toaddr - addr - count));
785 sec->size -= count;
786
787 /* Adjust all the relocs. */
788 for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
789 /* Get the new reloc address. */
790 if ((irel->r_offset > addr && irel->r_offset < toaddr))
791 irel->r_offset -= count;
792
793 /* The reloc's own addresses are now ok. However, we need to readjust
794 the reloc's addend, i.e. the reloc's value if two conditions are met:
795 1.) the reloc is relative to a symbol in this section that
796 is located in front of the shrinked instruction
797 2.) symbol plus addend end up behind the shrinked instruction.
798
799 The most common case where this happens are relocs relative to
800 the section-start symbol.
801
802 This step needs to be done for all of the sections of the bfd. */
803 {
804 struct bfd_section *isec;
805
806 for (isec = abfd->sections; isec; isec = isec->next)
807 {
808 bfd_vma symval;
809 bfd_vma shrinked_insn_address;
810
811 if (isec->reloc_count == 0)
812 continue;
813
814 shrinked_insn_address = (sec->output_section->vma
815 + sec->output_offset + addr - count);
816
817 irel = elf_section_data (isec)->relocs;
818 /* PR 12161: Read in the relocs for this section if necessary. */
819 if (irel == NULL)
820 irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
821
822 for (irelend = irel + isec->reloc_count; irel < irelend; irel++)
823 {
824 /* Read this BFD's local symbols if we haven't done
825 so already. */
826 if (isymbuf == NULL && symtab_hdr->sh_info != 0)
827 {
828 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
829 if (isymbuf == NULL)
830 isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
831 symtab_hdr->sh_info, 0,
832 NULL, NULL, NULL);
833 if (isymbuf == NULL)
834 return FALSE;
835 }
836
837 /* Get the value of the symbol referred to by the reloc. */
838 if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
839 {
840 /* A local symbol. */
841 asection *sym_sec;
842
843 isym = isymbuf + ELF32_R_SYM (irel->r_info);
844 sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
845 symval = isym->st_value;
846 /* If the reloc is absolute, it will not have
847 a symbol or section associated with it. */
848 if (sym_sec == sec)
849 {
850 symval += sym_sec->output_section->vma
851 + sym_sec->output_offset;
852
853 if (debug_relax)
854 printf ("Checking if the relocation's "
855 "addend needs corrections.\n"
856 "Address of anchor symbol: 0x%x \n"
857 "Address of relocation target: 0x%x \n"
858 "Address of relaxed insn: 0x%x \n",
859 (unsigned int) symval,
860 (unsigned int) (symval + irel->r_addend),
861 (unsigned int) shrinked_insn_address);
862
863 if (symval <= shrinked_insn_address
864 && (symval + irel->r_addend) > shrinked_insn_address)
865 {
866 /* If there is an alignment boundary, we only need to
867 adjust addends that end up below the boundary. */
868 bfd_vma shrink_boundary = (toaddr
869 + sec->output_section->vma
870 + sec->output_offset);
871
872 if (debug_relax)
873 printf
874 ("Relocation's addend needed to be fixed \n");
875
876 if (!elf32_ft32_adjust_reloc_if_spans_insn (abfd, isec,
877 irel, symval,
878 shrinked_insn_address,
879 shrink_boundary,
880 count))
881 return FALSE;
882 }
883 }
884 /* else reference symbol is absolute. No adjustment needed. */
885 }
886 /* else...Reference symbol is extern. No need for adjusting
887 the addend. */
888 }
889 }
890 }
891
892 /* Adjust the local symbols defined in this section. */
893 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
894 isym = (Elf_Internal_Sym *) symtab_hdr->contents;
895 if (isym)
896 {
897 for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
898 {
899 if (isym->st_shndx == sec_shndx
900 && isym->st_value > addr && isym->st_value < toaddr)
901 isym->st_value -= count;
902 }
903 }
904
905 /* Now adjust the global symbols defined in this section. */
906 symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
907 - symtab_hdr->sh_info);
908 sym_hashes = start_hashes = elf_sym_hashes (abfd);
909 end_hashes = sym_hashes + symcount;
910
911 for (; sym_hashes < end_hashes; sym_hashes++)
912 {
913 struct elf_link_hash_entry *sym_hash = *sym_hashes;
914
915 /* The '--wrap SYMBOL' option is causing a pain when the object file,
916 containing the definition of __wrap_SYMBOL, includes a direct
917 call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference
918 the same symbol (which is __wrap_SYMBOL), but still exist as two
919 different symbols in 'sym_hashes', we don't want to adjust
920 the global symbol __wrap_SYMBOL twice.
921 This check is only relevant when symbols are being wrapped. */
922 if (link_info->wrap_hash != NULL)
923 {
924 struct elf_link_hash_entry **cur_sym_hashes;
925
926 /* Loop only over the symbols whom been already checked. */
927 for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes;
928 cur_sym_hashes++)
929 /* If the current symbol is identical to 'sym_hash', that means
930 the symbol was already adjusted (or at least checked). */
931 if (*cur_sym_hashes == sym_hash)
932 break;
933
934 /* Don't adjust the symbol again. */
935 if (cur_sym_hashes < sym_hashes)
936 continue;
937 }
938
939 if ((sym_hash->root.type == bfd_link_hash_defined
940 || sym_hash->root.type == bfd_link_hash_defweak)
941 && sym_hash->root.u.def.section == sec
942 && sym_hash->root.u.def.value > addr
943 && sym_hash->root.u.def.value < toaddr)
944 sym_hash->root.u.def.value -= count;
945 }
946
947 return TRUE;
948 }
949
950 /* Return TRUE if LOC can be a target of a branch, jump or call. */
951
952 static bfd_boolean
953 elf32_ft32_relax_is_branch_target (struct bfd_link_info *link_info,
954 bfd * abfd, asection * sec,
955 bfd_vma loc)
956 {
957 Elf_Internal_Shdr *symtab_hdr;
958 Elf_Internal_Rela *irel, *irelend;
959 Elf_Internal_Sym *isym;
960 Elf_Internal_Sym *isymbuf = NULL;
961 bfd_vma symval;
962 struct bfd_section *isec;
963
964 struct elf_link_hash_entry **sym_hashes;
965 struct elf_link_hash_entry **end_hashes;
966 struct elf_link_hash_entry **start_hashes;
967 unsigned int symcount;
968
969 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
970
971 /* Now we check for relocations pointing to ret. */
972 for (isec = abfd->sections; isec; isec = isec->next)
973 {
974 irel = elf_section_data (isec)->relocs;
975 if (irel == NULL)
976 irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
977
978 irelend = irel + isec->reloc_count;
979
980 for (; irel < irelend; irel++)
981 {
982 /* Read this BFD's local symbols if we haven't done
983 so already. */
984 if (isymbuf == NULL && symtab_hdr->sh_info != 0)
985 {
986 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
987 if (isymbuf == NULL)
988 isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
989 symtab_hdr->sh_info, 0,
990 NULL, NULL, NULL);
991 if (isymbuf == NULL)
992 return FALSE;
993 }
994
995 /* Get the value of the symbol referred to by the reloc. */
996 if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
997 {
998 /* A local symbol. */
999 asection *sym_sec;
1000
1001 isym = isymbuf + ELF32_R_SYM (irel->r_info);
1002 sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1003 symval = isym->st_value;
1004 /* If the reloc is absolute, it will not have
1005 a symbol or section associated with it. */
1006 if (sym_sec == sec)
1007 {
1008 symval += sym_sec->output_section->vma
1009 + sym_sec->output_offset;
1010
1011 if (debug_relax)
1012 printf ("0x%x: Address of anchor symbol: 0x%x "
1013 "Address of relocation target: 0x%x \n",
1014 (unsigned int) irel->r_offset,
1015 (unsigned int) symval,
1016 (unsigned int) (symval + irel->r_addend));
1017 if ((irel->r_addend) == loc)
1018 return TRUE;
1019 }
1020 }
1021 }
1022 }
1023
1024 symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
1025 - symtab_hdr->sh_info);
1026 sym_hashes = start_hashes = elf_sym_hashes (abfd);
1027 end_hashes = sym_hashes + symcount;
1028
1029 for (; sym_hashes < end_hashes; sym_hashes++)
1030 {
1031 struct elf_link_hash_entry *sym_hash = *sym_hashes;
1032
1033 /* The '--wrap SYMBOL' option is causing a pain when the object file,
1034 containing the definition of __wrap_SYMBOL, includes a direct
1035 call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference
1036 the same symbol (which is __wrap_SYMBOL), but still exist as two
1037 different symbols in 'sym_hashes', we don't want to adjust
1038 the global symbol __wrap_SYMBOL twice.
1039 This check is only relevant when symbols are being wrapped. */
1040 if (link_info->wrap_hash != NULL)
1041 {
1042 struct elf_link_hash_entry **cur_sym_hashes;
1043
1044 /* Loop only over the symbols whom been already checked. */
1045 for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes;
1046 cur_sym_hashes++)
1047 /* If the current symbol is identical to 'sym_hash', that means
1048 the symbol was already adjusted (or at least checked). */
1049 if (*cur_sym_hashes == sym_hash)
1050 break;
1051
1052 /* Don't adjust the symbol again. */
1053 if (cur_sym_hashes < sym_hashes)
1054 continue;
1055 }
1056
1057 if ((sym_hash->root.type == bfd_link_hash_defined
1058 || sym_hash->root.type == bfd_link_hash_defweak)
1059 && sym_hash->root.u.def.section == sec
1060 && sym_hash->root.u.def.value == loc)
1061 return TRUE;
1062 }
1063
1064 return FALSE;
1065 }
1066
1067 static bfd_boolean
1068 ft32_elf_relax_section
1069 (bfd * abfd,
1070 asection * sec,
1071 struct bfd_link_info * link_info,
1072 bfd_boolean * again)
1073 {
1074 Elf_Internal_Rela * free_relocs = NULL;
1075 Elf_Internal_Rela * internal_relocs;
1076 Elf_Internal_Rela * irelend;
1077 Elf_Internal_Rela * irel;
1078 bfd_byte * contents = NULL;
1079 Elf_Internal_Shdr * symtab_hdr;
1080 Elf_Internal_Sym * isymbuf = NULL;
1081
1082 /* Assume nothing changes. */
1083 *again = FALSE;
1084
1085 /* We don't have to do anything for a relocatable link, if
1086 this section does not have relocs, or if this is not a
1087 code section. */
1088 if (bfd_link_relocatable (link_info)
1089 || (sec->flags & SEC_RELOC) == 0
1090 || sec->reloc_count == 0
1091 || (sec->flags & SEC_CODE) == 0)
1092 return TRUE;
1093
1094 /* Get the section contents. */
1095 if (elf_section_data (sec)->this_hdr.contents != NULL)
1096 contents = elf_section_data (sec)->this_hdr.contents;
1097 /* Go get them off disk. */
1098 else
1099 {
1100 if (! bfd_malloc_and_get_section (abfd, sec, &contents))
1101 goto error_return;
1102 elf_section_data (sec)->this_hdr.contents = contents;
1103 }
1104
1105 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1106
1107 /* Read this BFD's local symbols if we haven't done so already. */
1108 if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1109 {
1110 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1111 if (isymbuf == NULL)
1112 isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1113 symtab_hdr->sh_info, 0,
1114 NULL, NULL, NULL);
1115 if (isymbuf == NULL)
1116 goto error_return;
1117 symtab_hdr->contents = (unsigned char *) isymbuf;
1118 }
1119
1120 internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
1121 link_info->keep_memory);
1122 if (internal_relocs == NULL)
1123 goto error_return;
1124 if (! link_info->keep_memory)
1125 free_relocs = internal_relocs;
1126
1127 /* Walk through them looking for relaxing opportunities. */
1128 irelend = internal_relocs + sec->reloc_count;
1129
1130 /* Test every adjacent pair of relocs. If both have shortcodes,
1131 fuse them and delete the relocs. */
1132 irel = internal_relocs;
1133 while (irel < irelend - 1)
1134 {
1135 Elf_Internal_Rela * irel_next = irel + 1;
1136 unsigned int sc0, sc1;
1137 bfd_vma pc;
1138
1139 pc = irel->r_offset;
1140
1141 if (((pc + 4) == (irel_next->r_offset))
1142 && ft32_reloc_shortable (abfd, sec, isymbuf, contents, pc, irel,
1143 &sc0)
1144 && ft32_reloc_shortable (abfd, sec, isymbuf, contents, pc,
1145 irel_next, &sc1)
1146 && !elf32_ft32_relax_is_branch_target (link_info, abfd, sec,
1147 irel_next->r_offset))
1148 {
1149 unsigned int code30 = (sc1 << 15) | sc0;
1150 unsigned int code27 = code30 >> 3;
1151 unsigned int code3 = code30 & 7;
1152 static const unsigned char pat3[] = {2, 3, 4, 5, 6, 9, 10, 14};
1153 unsigned int pattern = pat3[code3];
1154 unsigned int fused = (pattern << 27) | code27;
1155
1156 /* Move second reloc to same place as first. */
1157 irel_next->r_offset = irel->r_offset;
1158
1159 /* Change both relocs to R_FT32_NONE. */
1160
1161 if (ELF32_R_TYPE (irel->r_info) == R_FT32_18)
1162 {
1163 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1164 R_FT32_SC0);
1165 }
1166 else
1167 {
1168 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1169 R_FT32_NONE);
1170 }
1171
1172 if (ELF32_R_TYPE (irel_next->r_info) == R_FT32_18)
1173 {
1174 irel_next->r_info = ELF32_R_INFO (ELF32_R_SYM (irel_next->r_info),
1175 R_FT32_SC1);
1176 }
1177 else
1178 {
1179 irel_next->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1180 R_FT32_NONE);
1181 }
1182
1183 /* Replace the first insn with the fused version. */
1184 bfd_put_32 (abfd, fused, contents + irel->r_offset);
1185
1186 /* Delete the second insn. */
1187 if (!elf32_ft32_relax_delete_bytes (link_info, abfd, sec,
1188 irel->r_offset + 4, 4))
1189 goto error_return;
1190
1191 /* That will change things, so, we should relax again.
1192 Note that this is not required, and it may be slow. */
1193 *again = TRUE;
1194
1195 irel += 2;
1196 }
1197 else
1198 {
1199 irel += 1;
1200 }
1201 }
1202
1203 if (isymbuf != NULL
1204 && symtab_hdr->contents != (unsigned char *) isymbuf)
1205 {
1206 if (! link_info->keep_memory)
1207 free (isymbuf);
1208 else
1209 /* Cache the symbols for elf_link_input_bfd. */
1210 symtab_hdr->contents = (unsigned char *) isymbuf;
1211 }
1212
1213 if (contents != NULL
1214 && elf_section_data (sec)->this_hdr.contents != contents)
1215 {
1216 if (! link_info->keep_memory)
1217 free (contents);
1218 else
1219 /* Cache the section contents for elf_link_input_bfd. */
1220 elf_section_data (sec)->this_hdr.contents = contents;
1221
1222 }
1223
1224 if (internal_relocs != NULL
1225 && elf_section_data (sec)->relocs != internal_relocs)
1226 free (internal_relocs);
1227
1228 return TRUE;
1229
1230 error_return:
1231 if (free_relocs != NULL)
1232 free (free_relocs);
1233
1234 return TRUE;
1235 }
1236 \f
1237 #define ELF_ARCH bfd_arch_ft32
1238 #define ELF_MACHINE_CODE EM_FT32
1239 #define ELF_MAXPAGESIZE 0x1
1240
1241 #define TARGET_LITTLE_SYM ft32_elf32_vec
1242 #define TARGET_LITTLE_NAME "elf32-ft32"
1243
1244 #define elf_info_to_howto_rel NULL
1245 #define elf_info_to_howto ft32_info_to_howto_rela
1246 #define elf_backend_relocate_section ft32_elf_relocate_section
1247
1248 #define elf_backend_can_gc_sections 1
1249 #define elf_backend_rela_normal 1
1250
1251 #define bfd_elf32_bfd_reloc_type_lookup ft32_reloc_type_lookup
1252 #define bfd_elf32_bfd_reloc_name_lookup ft32_reloc_name_lookup
1253
1254 #define bfd_elf32_bfd_relax_section ft32_elf_relax_section
1255
1256 #include "elf32-target.h"
This page took 0.07415 seconds and 5 git commands to generate.