packaging: Enable testing infrastructure
[external/binutils.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"