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
33static 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_signed, /* 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};
151
152/* Map BFD reloc types to FT32 ELF reloc types.  */
153
154struct ft32_reloc_map
155{
156  bfd_reloc_code_real_type bfd_reloc_val;
157  unsigned int ft32_reloc_val;
158};
159
160static const struct ft32_reloc_map ft32_reloc_map [] =
161{
162  { BFD_RELOC_NONE,            R_FT32_NONE },
163  { BFD_RELOC_32,              R_FT32_32 },
164  { BFD_RELOC_16,              R_FT32_16 },
165  { BFD_RELOC_8,               R_FT32_8 },
166  { BFD_RELOC_FT32_10,           R_FT32_10 },
167  { BFD_RELOC_FT32_20,           R_FT32_20 },
168  { BFD_RELOC_FT32_17,           R_FT32_17 },
169  { BFD_RELOC_FT32_18,           R_FT32_18 },
170};
171
172static reloc_howto_type *
173ft32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
174			 bfd_reloc_code_real_type code)
175{
176  unsigned int i;
177
178  for (i = sizeof (ft32_reloc_map) / sizeof (ft32_reloc_map[0]);
179       --i;)
180    if (ft32_reloc_map [i].bfd_reloc_val == code)
181      return & ft32_elf_howto_table [ft32_reloc_map[i].ft32_reloc_val];
182
183  return NULL;
184}
185
186static reloc_howto_type *
187ft32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
188{
189  unsigned int i;
190
191  for (i = 0;
192       i < sizeof (ft32_elf_howto_table) / sizeof (ft32_elf_howto_table[0]);
193       i++)
194    if (ft32_elf_howto_table[i].name != NULL
195	&& strcasecmp (ft32_elf_howto_table[i].name, r_name) == 0)
196      return &ft32_elf_howto_table[i];
197
198  return NULL;
199}
200
201/* Set the howto pointer for an FT32 ELF reloc.  */
202
203static void
204ft32_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
205			  arelent *cache_ptr,
206			  Elf_Internal_Rela *dst)
207{
208  unsigned int r_type;
209
210  r_type = ELF32_R_TYPE (dst->r_info);
211  BFD_ASSERT (r_type < (unsigned int) R_FT32_max);
212  cache_ptr->howto = & ft32_elf_howto_table [r_type];
213}
214
215/* Relocate an FT32 ELF section.
216
217   The RELOCATE_SECTION function is called by the new ELF backend linker
218   to handle the relocations for a section.
219
220   The relocs are always passed as Rela structures; if the section
221   actually uses Rel structures, the r_addend field will always be
222   zero.
223
224   This function is responsible for adjusting the section contents as
225   necessary, and (if using Rela relocs and generating a relocatable
226   output file) adjusting the reloc addend as necessary.
227
228   This function does not have to worry about setting the reloc
229   address or the reloc symbol index.
230
231   LOCAL_SYMS is a pointer to the swapped in local symbols.
232
233   LOCAL_SECTIONS is an array giving the section in the input file
234   corresponding to the st_shndx field of each local symbol.
235
236   The global hash table entry for the global symbols can be found
237   via elf_sym_hashes (input_bfd).
238
239   When generating relocatable output, this function must handle
240   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
241   going to be the section symbol corresponding to the output
242   section, which means that the addend must be adjusted
243   accordingly.  */
244
245static bfd_boolean
246ft32_elf_relocate_section (bfd *output_bfd,
247			    struct bfd_link_info *info,
248			    bfd *input_bfd,
249			    asection *input_section,
250			    bfd_byte *contents,
251			    Elf_Internal_Rela *relocs,
252			    Elf_Internal_Sym *local_syms,
253			    asection **local_sections)
254{
255  Elf_Internal_Shdr *symtab_hdr;
256  struct elf_link_hash_entry **sym_hashes;
257  Elf_Internal_Rela *rel;
258  Elf_Internal_Rela *relend;
259
260  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
261  sym_hashes = elf_sym_hashes (input_bfd);
262  relend     = relocs + input_section->reloc_count;
263
264  for (rel = relocs; rel < relend; rel ++)
265    {
266      reloc_howto_type *howto;
267      unsigned long r_symndx;
268      Elf_Internal_Sym *sym;
269      asection *sec;
270      struct elf_link_hash_entry *h;
271      bfd_vma relocation;
272      bfd_reloc_status_type r;
273      const char *name;
274      int r_type;
275
276      r_type = ELF32_R_TYPE (rel->r_info);
277      r_symndx = ELF32_R_SYM (rel->r_info);
278      howto  = ft32_elf_howto_table + r_type;
279      h      = NULL;
280      sym    = NULL;
281      sec    = NULL;
282
283      if (r_symndx < symtab_hdr->sh_info)
284	{
285	  sym = local_syms + r_symndx;
286	  sec = local_sections [r_symndx];
287	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
288
289	  name = bfd_elf_string_from_elf_section
290	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
291	  name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
292	}
293      else
294	{
295	  bfd_boolean unresolved_reloc, warned, ignored;
296
297	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
298				   r_symndx, symtab_hdr, sym_hashes,
299				   h, sec, relocation,
300				   unresolved_reloc, warned, ignored);
301
302	  name = h->root.root.string;
303	}
304
305      if (sec != NULL && discarded_section (sec))
306	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
307					 rel, 1, relend, howto, 0, contents);
308
309      if (bfd_link_relocatable (info))
310	continue;
311
312      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
313				    contents, rel->r_offset,
314				    relocation, rel->r_addend);
315
316      if (r != bfd_reloc_ok)
317	{
318	  const char * msg = NULL;
319
320	  switch (r)
321	    {
322	    case bfd_reloc_overflow:
323	      (*info->callbacks->reloc_overflow)
324		(info, (h ? &h->root : NULL), name, howto->name,
325		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
326	      break;
327
328	    case bfd_reloc_undefined:
329	      (*info->callbacks->undefined_symbol)
330		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
331	      break;
332
333	    case bfd_reloc_outofrange:
334	      msg = _("internal error: out of range error");
335	      break;
336
337	    case bfd_reloc_notsupported:
338	      msg = _("internal error: unsupported relocation error");
339	      break;
340
341	    case bfd_reloc_dangerous:
342	      msg = _("internal error: dangerous relocation");
343	      break;
344
345	    default:
346	      msg = _("internal error: unknown error");
347	      break;
348	    }
349
350	  if (msg)
351	    (*info->callbacks->warning) (info, msg, name, input_bfd,
352					 input_section, rel->r_offset);
353	}
354    }
355
356  return TRUE;
357}
358
359#define ELF_ARCH		bfd_arch_ft32
360#define ELF_MACHINE_CODE	EM_FT32
361#define ELF_MAXPAGESIZE		0x1
362
363#define TARGET_LITTLE_SYM       ft32_elf32_vec
364#define TARGET_LITTLE_NAME	"elf32-ft32"
365
366#define elf_info_to_howto_rel			NULL
367#define elf_info_to_howto			ft32_info_to_howto_rela
368#define elf_backend_relocate_section		ft32_elf_relocate_section
369
370#define elf_backend_can_gc_sections		1
371#define elf_backend_rela_normal			1
372
373#define bfd_elf32_bfd_reloc_type_lookup		ft32_reloc_type_lookup
374#define bfd_elf32_bfd_reloc_name_lookup		ft32_reloc_name_lookup
375
376#include "elf32-target.h"
377