FT32: support for FT32B processor - part 1
[external/binutils.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
31 /* Forward declarations.  */
32
33 static reloc_howto_type ft32_elf_howto_table [] =
34 {
35   /* This reloc does nothing.  */
36   HOWTO (R_FT32_NONE,           /* type */
37          0,                     /* rightshift */
38          2,                     /* size (0 = byte, 1 = short, 2 = long) */
39          32,                    /* bitsize */
40          FALSE,                 /* pc_relative */
41          0,                     /* bitpos */
42          complain_overflow_bitfield, /* complain_on_overflow */
43          bfd_elf_generic_reloc, /* special_function */
44          "R_FT32_NONE",         /* name */
45          FALSE,                 /* partial_inplace */
46          0,                     /* src_mask */
47          0,                     /* dst_mask */
48          FALSE),                /* pcrel_offset */
49
50   /* A 32 bit absolute relocation.  */
51
52   HOWTO (R_FT32_32,             /* type */
53          0,                     /* rightshift */
54          2,                     /* size (0 = byte, 1 = short, 2 = long) */
55          32,                    /* bitsize */
56          FALSE,                 /* pc_relative */
57          0,                     /* bitpos */
58          complain_overflow_bitfield, /* complain_on_overflow */
59          bfd_elf_generic_reloc, /* special_function */
60          "R_FT32_32",           /* name */
61          FALSE,                 /* partial_inplace */
62          0x00000000,            /* src_mask */
63          0xffffffff,            /* dst_mask */
64          FALSE),                /* pcrel_offset */
65
66   HOWTO (R_FT32_16,             /* type */
67          0,                     /* rightshift */
68          1,                     /* size (0 = byte, 1 = short, 2 = long) */
69          16,                    /* bitsize */
70          FALSE,                 /* pc_relative */
71          0,                     /* bitpos */
72          complain_overflow_bitfield, /* complain_on_overflow */
73          bfd_elf_generic_reloc, /* special_function */
74          "R_FT32_16",           /* name */
75          FALSE,                 /* partial_inplace */
76          0x00000000,            /* src_mask */
77          0x0000ffff,            /* dst_mask */
78          FALSE),                /* pcrel_offset */
79
80   HOWTO (R_FT32_8,              /* type */
81          0,                     /* rightshift */
82          0,                     /* size (0 = byte, 1 = short, 2 = long) */
83          8,                     /* bitsize */
84          FALSE,                 /* pc_relative */
85          0,                     /* bitpos */
86          complain_overflow_signed, /* complain_on_overflow */
87          bfd_elf_generic_reloc, /* special_function */
88          "R_FT32_8",            /* name */
89          FALSE,                 /* partial_inplace */
90          0x00000000,            /* src_mask */
91          0x000000ff,            /* dst_mask */
92          FALSE),                /* pcrel_offset */
93
94   HOWTO (R_FT32_10,             /* type */
95          0,                     /* rightshift */
96          1,                     /* size (0 = byte, 1 = short, 2 = long) */
97          10,                    /* bitsize */
98          FALSE,                 /* pc_relative */
99          4,                     /* bitpos */
100          complain_overflow_signed, /* complain_on_overflow */
101          bfd_elf_generic_reloc, /* special_function */
102          "R_FT32_10",           /* name */
103          FALSE,                 /* partial_inplace */
104          0x00000000,            /* src_mask */
105          0x00003ff0,            /* dst_mask */
106          FALSE),                /* pcrel_offset */
107
108   HOWTO (R_FT32_20,             /* type */
109          0,                     /* rightshift */
110          2,                     /* size (0 = byte, 1 = short, 2 = long) */
111          20,                    /* bitsize */
112          FALSE,                 /* pc_relative */
113          0,                     /* bitpos */
114          complain_overflow_dont, /* complain_on_overflow */
115          bfd_elf_generic_reloc, /* special_function */
116          "R_FT32_20",           /* name */
117          FALSE,                 /* partial_inplace */
118          0x00000000,            /* src_mask */
119          0x000fffff,            /* dst_mask */
120          FALSE),                /* pcrel_offset */
121
122   HOWTO (R_FT32_17,             /* type */
123          0,                     /* rightshift */
124          2,                     /* size (0 = byte, 1 = short, 2 = long) */
125          17,                    /* bitsize */
126          FALSE,                 /* pc_relative */
127          0,                     /* bitpos */
128          complain_overflow_dont, /* complain_on_overflow */
129          bfd_elf_generic_reloc, /* special_function */
130          "R_FT32_17",           /* name */
131          FALSE,                 /* partial_inplace */
132          0x00000000,            /* src_mask */
133          0x0001ffff,            /* dst_mask */
134          FALSE),                /* pcrel_offset */
135
136   HOWTO (R_FT32_18,             /* type */
137          2,                     /* rightshift */
138          2,                     /* size (0 = byte, 1 = short, 2 = long) */
139          18,                    /* bitsize */
140          FALSE,                 /* pc_relative */
141          0,                     /* bitpos */
142          complain_overflow_dont, /* complain_on_overflow */
143          bfd_elf_generic_reloc, /* special_function */
144          "R_FT32_18",           /* name */
145          FALSE,         /* partial_inplace */
146          0x00000000,            /* src_mask */
147          0x0003ffff,            /* dst_mask */
148          FALSE),                /* pcrel_offset */
149
150   HOWTO (R_FT32_15,             /* type */
151          0,                     /* rightshift */
152          2,                     /* size (0 = byte, 1 = short, 2 = long) */
153          15,                    /* bitsize */
154          FALSE,                 /* pc_relative */
155          0,                     /* bitpos */
156          complain_overflow_dont, /* complain_on_overflow */
157          bfd_elf_generic_reloc, /* special_function */
158          "R_FT32_15",           /* name */
159          FALSE,                 /* partial_inplace */
160          0x00000000,            /* src_mask */
161          0x00007fff,            /* dst_mask */
162          FALSE),                /* pcrel_offset */
163 };
164 \f
165 /* Map BFD reloc types to FT32 ELF reloc types.  */
166
167 struct ft32_reloc_map
168 {
169   bfd_reloc_code_real_type bfd_reloc_val;
170   unsigned int ft32_reloc_val;
171 };
172
173 static const struct ft32_reloc_map ft32_reloc_map [] =
174 {
175   { BFD_RELOC_NONE,            R_FT32_NONE },
176   { BFD_RELOC_32,              R_FT32_32 },
177   { BFD_RELOC_16,              R_FT32_16 },
178   { BFD_RELOC_8,               R_FT32_8 },
179   { BFD_RELOC_FT32_10,           R_FT32_10 },
180   { BFD_RELOC_FT32_20,           R_FT32_20 },
181   { BFD_RELOC_FT32_17,           R_FT32_17 },
182   { BFD_RELOC_FT32_18,           R_FT32_18 },
183   { BFD_RELOC_FT32_15,          R_FT32_15 },
184 };
185
186 static reloc_howto_type *
187 ft32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
188                          bfd_reloc_code_real_type code)
189 {
190   unsigned int i;
191
192   for (i = sizeof (ft32_reloc_map) / sizeof (ft32_reloc_map[0]);
193        --i;)
194     if (ft32_reloc_map [i].bfd_reloc_val == code)
195       return & ft32_elf_howto_table [ft32_reloc_map[i].ft32_reloc_val];
196
197   return NULL;
198 }
199
200 static reloc_howto_type *
201 ft32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
202 {
203   unsigned int i;
204
205   for (i = 0;
206        i < sizeof (ft32_elf_howto_table) / sizeof (ft32_elf_howto_table[0]);
207        i++)
208     if (ft32_elf_howto_table[i].name != NULL
209         && strcasecmp (ft32_elf_howto_table[i].name, r_name) == 0)
210       return &ft32_elf_howto_table[i];
211
212   return NULL;
213 }
214
215 /* Set the howto pointer for an FT32 ELF reloc.  */
216
217 static void
218 ft32_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
219                           arelent *cache_ptr,
220                           Elf_Internal_Rela *dst)
221 {
222   unsigned int r_type;
223
224   r_type = ELF32_R_TYPE (dst->r_info);
225   BFD_ASSERT (r_type < (unsigned int) R_FT32_max);
226   cache_ptr->howto = & ft32_elf_howto_table [r_type];
227 }
228 \f
229 /* Relocate an FT32 ELF section.
230
231    The RELOCATE_SECTION function is called by the new ELF backend linker
232    to handle the relocations for a section.
233
234    The relocs are always passed as Rela structures; if the section
235    actually uses Rel structures, the r_addend field will always be
236    zero.
237
238    This function is responsible for adjusting the section contents as
239    necessary, and (if using Rela relocs and generating a relocatable
240    output file) adjusting the reloc addend as necessary.
241
242    This function does not have to worry about setting the reloc
243    address or the reloc symbol index.
244
245    LOCAL_SYMS is a pointer to the swapped in local symbols.
246
247    LOCAL_SECTIONS is an array giving the section in the input file
248    corresponding to the st_shndx field of each local symbol.
249
250    The global hash table entry for the global symbols can be found
251    via elf_sym_hashes (input_bfd).
252
253    When generating relocatable output, this function must handle
254    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
255    going to be the section symbol corresponding to the output
256    section, which means that the addend must be adjusted
257    accordingly.  */
258
259 static bfd_boolean
260 ft32_elf_relocate_section (bfd *output_bfd,
261                             struct bfd_link_info *info,
262                             bfd *input_bfd,
263                             asection *input_section,
264                             bfd_byte *contents,
265                             Elf_Internal_Rela *relocs,
266                             Elf_Internal_Sym *local_syms,
267                             asection **local_sections)
268 {
269   Elf_Internal_Shdr *symtab_hdr;
270   struct elf_link_hash_entry **sym_hashes;
271   Elf_Internal_Rela *rel;
272   Elf_Internal_Rela *relend;
273
274   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
275   sym_hashes = elf_sym_hashes (input_bfd);
276   relend     = relocs + input_section->reloc_count;
277
278   for (rel = relocs; rel < relend; rel ++)
279     {
280       reloc_howto_type *howto;
281       unsigned long r_symndx;
282       Elf_Internal_Sym *sym;
283       asection *sec;
284       struct elf_link_hash_entry *h;
285       bfd_vma relocation;
286       bfd_reloc_status_type r;
287       const char *name;
288       int r_type;
289
290       r_type = ELF32_R_TYPE (rel->r_info);
291       r_symndx = ELF32_R_SYM (rel->r_info);
292       howto  = ft32_elf_howto_table + r_type;
293       h      = NULL;
294       sym    = NULL;
295       sec    = NULL;
296
297       if (r_symndx < symtab_hdr->sh_info)
298         {
299           sym = local_syms + r_symndx;
300           sec = local_sections [r_symndx];
301           relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
302
303           name = bfd_elf_string_from_elf_section
304             (input_bfd, symtab_hdr->sh_link, sym->st_name);
305           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
306         }
307       else
308         {
309           bfd_boolean unresolved_reloc, warned, ignored;
310
311           RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
312                                    r_symndx, symtab_hdr, sym_hashes,
313                                    h, sec, relocation,
314                                    unresolved_reloc, warned, ignored);
315
316           name = h->root.root.string;
317         }
318
319       if (sec != NULL && discarded_section (sec))
320         RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
321                                          rel, 1, relend, howto, 0, contents);
322
323       if (bfd_link_relocatable (info))
324         continue;
325
326       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
327                                     contents, rel->r_offset,
328                                     relocation, rel->r_addend);
329
330       if (r != bfd_reloc_ok)
331         {
332           const char * msg = NULL;
333
334           switch (r)
335             {
336             case bfd_reloc_overflow:
337               (*info->callbacks->reloc_overflow)
338                 (info, (h ? &h->root : NULL), name, howto->name,
339                  (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
340               break;
341
342             case bfd_reloc_undefined:
343               (*info->callbacks->undefined_symbol)
344                 (info, name, input_bfd, input_section, rel->r_offset, TRUE);
345               break;
346
347             case bfd_reloc_outofrange:
348               msg = _("internal error: out of range error");
349               break;
350
351             case bfd_reloc_notsupported:
352               msg = _("internal error: unsupported relocation error");
353               break;
354
355             case bfd_reloc_dangerous:
356               msg = _("internal error: dangerous relocation");
357               break;
358
359             default:
360               msg = _("internal error: unknown error");
361               break;
362             }
363
364           if (msg)
365             (*info->callbacks->warning) (info, msg, name, input_bfd,
366                                          input_section, rel->r_offset);
367         }
368     }
369
370   return TRUE;
371 }
372 \f
373 #define ELF_ARCH                bfd_arch_ft32
374 #define ELF_MACHINE_CODE        EM_FT32
375 #define ELF_MAXPAGESIZE         0x1
376
377 #define TARGET_LITTLE_SYM       ft32_elf32_vec
378 #define TARGET_LITTLE_NAME      "elf32-ft32"
379
380 #define elf_info_to_howto_rel                   NULL
381 #define elf_info_to_howto                       ft32_info_to_howto_rela
382 #define elf_backend_relocate_section            ft32_elf_relocate_section
383
384 #define elf_backend_can_gc_sections             1
385 #define elf_backend_rela_normal                 1
386
387 #define bfd_elf32_bfd_reloc_type_lookup         ft32_reloc_type_lookup
388 #define bfd_elf32_bfd_reloc_name_lookup         ft32_reloc_name_lookup
389
390 #include "elf32-target.h"