1/* Infineon XC16X-specific support for 16-bit ELF.
2   Copyright (C) 2006-2017 Free Software Foundation, Inc.
3   Contributed by KPIT Cummins Infosystems
4
5   This file is part of BFD, the Binary File Descriptor library.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22#include "sysdep.h"
23#include "bfd.h"
24#include "libbfd.h"
25#include "elf-bfd.h"
26#include "elf/xc16x.h"
27#include "dwarf2.h"
28#include "libiberty.h"
29
30static reloc_howto_type xc16x_elf_howto_table [] =
31{
32  /* This reloc does nothing.  */
33  HOWTO (R_XC16X_NONE,		/* type */
34	 0,			/* rightshift */
35	 3,			/* size (0 = byte, 1 = short, 2 = long) */
36	 0,			/* bitsize */
37	 FALSE,			/* pc_relative */
38	 0,			/* bitpos */
39	 complain_overflow_dont, /* complain_on_overflow */
40	 bfd_elf_generic_reloc,	/* special_function */
41	 "R_XC16X_NONE",	/* name */
42	 FALSE,			/* partial_inplace */
43	 0,			/* src_mask */
44	 0,			/* dst_mask */
45	 FALSE),		/* pcrel_offset */
46
47  /* An 8 bit absolute relocation.  */
48  HOWTO (R_XC16X_ABS_8,		/* type */
49	 0,			/* rightshift */
50	 0,			/* size (0 = byte, 1 = short, 2 = long) */
51	 8,			/* bitsize */
52	 FALSE,			/* pc_relative */
53	 8,			/* bitpos */
54	 complain_overflow_bitfield, /* complain_on_overflow */
55	 bfd_elf_generic_reloc,	/* special_function */
56	 "R_XC16X_ABS_8",	/* name */
57	 TRUE,			/* partial_inplace */
58	 0x0000,		/* src_mask */
59	 0x00ff,		/* dst_mask */
60	 FALSE),		/* pcrel_offset */
61
62  /* A 16 bit absolute relocation.  */
63  HOWTO (R_XC16X_ABS_16,	/* type */
64	 0,			/* rightshift */
65	 1,			/* size (0 = byte, 1 = short, 2 = long) */
66	 16,			/* bitsize */
67	 FALSE,			/* pc_relative */
68	 0,			/* bitpos */
69	 complain_overflow_dont, /* complain_on_overflow */
70	 bfd_elf_generic_reloc,	/* special_function */
71	 "R_XC16X_ABS_16",	/* name */
72	 TRUE,			/* partial_inplace */
73	 0x00000000,		/* src_mask */
74	 0x0000ffff,		/* dst_mask */
75	 FALSE),		/* pcrel_offset */
76
77  HOWTO (R_XC16X_ABS_32,	/* type */
78  	 0,			/* rightshift */
79  	 2,			/* size (0 = byte, 1 = short, 2 = long) */
80  	 32,			/* bitsize */
81  	 FALSE,			/* pc_relative */
82  	 0,			/* bitpos */
83  	 complain_overflow_bitfield, /* complain_on_overflow */
84  	 bfd_elf_generic_reloc,	/* special_function */
85  	 "R_XC16X_ABS_32",	/* name */
86  	 TRUE,			/* partial_inplace */
87  	 0x00000000,		/* src_mask */
88  	 0xffffffff,		/* dst_mask */
89  	 FALSE),		/* pcrel_offset */
90
91
92  /* A PC relative 8 bit relocation.  */
93  HOWTO (R_XC16X_8_PCREL,	/* type */
94	 0,			/* rightshift */
95	 0,			/* size (0 = byte, 1 = short, 2 = long) */
96	 8,			/* bitsize */
97	 TRUE,			/* pc_relative */
98	 8,			/* bitpos */
99	 complain_overflow_signed, /* complain_on_overflow */
100	 bfd_elf_generic_reloc, /* special_function */
101	 "R_XC16X_8_PCREL",	/* name */
102	 FALSE,			/* partial_inplace */
103	 0x0000,		/* src_mask */
104	 0x00ff,		/* dst_mask */
105	 TRUE),		/* pcrel_offset */
106
107  /* Relocation regarding page number.  */
108    HOWTO (R_XC16X_PAG,	/* type */
109  	 0,			/* rightshift */
110  	 1,			/* size (0 = byte, 1 = short, 2 = long) */
111  	 16,			/* bitsize */
112  	 FALSE,			/* pc_relative */
113  	 0,			/* bitpos */
114  	 complain_overflow_signed, /* complain_on_overflow */
115  	 bfd_elf_generic_reloc, /* special_function */
116  	 "R_XC16X_PAG",	/* name */
117  	 TRUE,			/* partial_inplace */
118  	 0x00000000,		/* src_mask */
119  	 0x0000ffff,		/* dst_mask */
120  	 FALSE),		/* pcrel_offset */
121
122
123  /* Relocation regarding page number.  */
124      HOWTO (R_XC16X_POF,	/* type */
125    	 0,			/* rightshift */
126    	 1,			/* size (0 = byte, 1 = short, 2 = long) */
127    	 16,			/* bitsize */
128    	 FALSE,			/* pc_relative */
129    	 0,			/* bitpos  */
130    	 complain_overflow_signed, /* complain_on_overflow  */
131    	 bfd_elf_generic_reloc, /* special_function  */
132    	 "R_XC16X_POF",	/* name  */
133    	 TRUE,			/* partial_inplace  */
134    	 0x00000000,		/* src_mask  */
135    	 0x0000ffff,		/* dst_mask  */
136    	 FALSE),		/* pcrel_offset  */
137
138
139  /* Relocation regarding segment number.   */
140      HOWTO (R_XC16X_SEG,	/* type  */
141    	 0,			/* rightshift  */
142    	 1,			/* size (0 = byte, 1 = short, 2 = long)  */
143    	 16,			/* bitsize  */
144    	 FALSE,			/* pc_relative  */
145    	 0,			/* bitpos  */
146    	 complain_overflow_signed, /* complain_on_overflow  */
147    	 bfd_elf_generic_reloc, /* special_function  */
148    	 "R_XC16X_SEG",	/* name  */
149    	 TRUE,			/* partial_inplace  */
150    	 0x00000000,		/* src_mask  */
151    	 0x0000ffff,		/* dst_mask  */
152    	 FALSE),		/* pcrel_offset  */
153
154  /* Relocation regarding segment offset.  */
155      HOWTO (R_XC16X_SOF,	/* type  */
156    	 0,			/* rightshift  */
157    	 1,			/* size (0 = byte, 1 = short, 2 = long)  */
158    	 16,			/* bitsize  */
159    	 FALSE,			/* pc_relative  */
160    	 0,			/* bitpos  */
161    	 complain_overflow_signed, /* complain_on_overflow  */
162    	 bfd_elf_generic_reloc, /* special_function  */
163    	 "R_XC16X_SOF",	/* name */
164    	 TRUE,			/* partial_inplace  */
165    	 0x00000000,		/* src_mask  */
166    	 0x0000ffff,		/* dst_mask  */
167    	 FALSE)			/* pcrel_offset  */
168};
169
170
171/* Map BFD reloc types to XC16X ELF reloc types.  */
172
173struct xc16x_reloc_map
174{
175  bfd_reloc_code_real_type bfd_reloc_val;
176  unsigned int xc16x_reloc_val;
177};
178
179static const struct xc16x_reloc_map xc16x_reloc_map [] =
180{
181  { BFD_RELOC_NONE,           R_XC16X_NONE },
182  { BFD_RELOC_8,              R_XC16X_ABS_8 },
183  { BFD_RELOC_16,             R_XC16X_ABS_16 },
184  { BFD_RELOC_32,             R_XC16X_ABS_32 },
185  { BFD_RELOC_8_PCREL,        R_XC16X_8_PCREL },
186  { BFD_RELOC_XC16X_PAG,      R_XC16X_PAG},
187  { BFD_RELOC_XC16X_POF,      R_XC16X_POF},
188  { BFD_RELOC_XC16X_SEG,      R_XC16X_SEG},
189  { BFD_RELOC_XC16X_SOF,      R_XC16X_SOF},
190};
191
192
193/* This function is used to search for correct relocation type from
194   howto structure.  */
195
196static reloc_howto_type *
197xc16x_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
198			 bfd_reloc_code_real_type code)
199{
200  unsigned int i;
201
202  for (i = ARRAY_SIZE (xc16x_reloc_map); --i;)
203    if (xc16x_reloc_map [i].bfd_reloc_val == code)
204      return & xc16x_elf_howto_table [xc16x_reloc_map[i].xc16x_reloc_val];
205
206  return NULL;
207}
208
209static reloc_howto_type *
210xc16x_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
211			 const char *r_name)
212{
213  unsigned int i;
214
215  for (i = 0;
216       i < sizeof (xc16x_elf_howto_table) / sizeof (xc16x_elf_howto_table[0]);
217       i++)
218    if (xc16x_elf_howto_table[i].name != NULL
219	&& strcasecmp (xc16x_elf_howto_table[i].name, r_name) == 0)
220      return &xc16x_elf_howto_table[i];
221
222  return NULL;
223}
224
225/* For a particular operand this function is
226   called to finalise the type of relocation.  */
227
228static void
229elf32_xc16x_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc,
230			   Elf_Internal_Rela *elf_reloc)
231{
232  unsigned int r;
233  unsigned int i;
234
235  r = ELF32_R_TYPE (elf_reloc->r_info);
236  for (i = 0; i < ARRAY_SIZE (xc16x_elf_howto_table); i++)
237    if (xc16x_elf_howto_table[i].type == r)
238      {
239	bfd_reloc->howto = &xc16x_elf_howto_table[i];
240	return;
241      }
242  abort ();
243}
244
245static bfd_reloc_status_type
246elf32_xc16x_final_link_relocate (unsigned long r_type,
247				 bfd *input_bfd,
248				 bfd *output_bfd ATTRIBUTE_UNUSED,
249				 asection *input_section ATTRIBUTE_UNUSED,
250				 bfd_byte *contents,
251				 bfd_vma offset,
252				 bfd_vma value,
253				 bfd_vma addend,
254				 struct bfd_link_info *info ATTRIBUTE_UNUSED,
255				 asection *sym_sec ATTRIBUTE_UNUSED,
256				 int is_local ATTRIBUTE_UNUSED)
257{
258  bfd_byte *hit_data = contents + offset;
259  bfd_vma val1;
260
261  switch (r_type)
262    {
263    case R_XC16X_NONE:
264      return bfd_reloc_ok;
265
266    case R_XC16X_ABS_16:
267      value += addend;
268      bfd_put_16 (input_bfd, value, hit_data);
269      return bfd_reloc_ok;
270
271    case R_XC16X_8_PCREL:
272      bfd_put_8 (input_bfd, value, hit_data);
273      return bfd_reloc_ok;
274
275      /* Following case is to find page number from actual
276	 address for this divide value by 16k i.e. page size.  */
277
278    case R_XC16X_PAG:
279      value += addend;
280      value /= 0x4000;
281      bfd_put_16 (input_bfd, value, hit_data);
282      return bfd_reloc_ok;
283
284      /* Following case is to find page offset from actual address
285	 for this take modulo of value by 16k i.e. page size.  */
286
287    case R_XC16X_POF:
288      value += addend;
289      value %= 0x4000;
290      bfd_put_16 (input_bfd, value, hit_data);
291      return bfd_reloc_ok;
292
293      /* Following case is to find segment number from actual
294	 address for this divide value by 64k i.e. segment size.  */
295
296    case R_XC16X_SEG:
297      value += addend;
298      value /= 0x10000;
299      bfd_put_16 (input_bfd, value, hit_data);
300      return bfd_reloc_ok;
301
302      /* Following case is to find segment offset from actual address
303	 for this take modulo of value by 64k i.e. segment size.  */
304
305    case R_XC16X_SOF:
306      value += addend;
307      value %= 0x10000;
308      bfd_put_16 (input_bfd, value, hit_data);
309      return bfd_reloc_ok;
310
311    case R_XC16X_ABS_32:
312      if (!strstr (input_section->name,".debug"))
313	{
314	  value += addend;
315	  val1 = value;
316	  value %= 0x4000;
317	  val1 /= 0x4000;
318	  val1 = val1 << 16;
319	  value += val1;
320	  bfd_put_32 (input_bfd, value, hit_data);
321	}
322      else
323	{
324	  value += addend;
325	  bfd_put_32 (input_bfd, value, hit_data);
326	}
327      return bfd_reloc_ok;
328
329    default:
330      return bfd_reloc_notsupported;
331    }
332}
333
334static bfd_boolean
335elf32_xc16x_relocate_section (bfd *output_bfd,
336			      struct bfd_link_info *info,
337			      bfd *input_bfd,
338			      asection *input_section,
339			      bfd_byte *contents,
340			      Elf_Internal_Rela *relocs,
341			      Elf_Internal_Sym *local_syms,
342			      asection **local_sections)
343{
344  Elf_Internal_Shdr *symtab_hdr;
345  struct elf_link_hash_entry **sym_hashes;
346  Elf_Internal_Rela *rel, *relend;
347
348  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
349  sym_hashes = elf_sym_hashes (input_bfd);
350
351  rel = relocs;
352  relend = relocs + input_section->reloc_count;
353  for (; rel < relend; rel++)
354    {
355      unsigned int r_type;
356      unsigned long r_symndx;
357      Elf_Internal_Sym *sym;
358      asection *sec;
359      struct elf_link_hash_entry *h;
360      bfd_vma relocation;
361
362      /* This is a final link.  */
363      r_symndx = ELF32_R_SYM (rel->r_info);
364      r_type = ELF32_R_TYPE (rel->r_info);
365      h = NULL;
366      sym = NULL;
367      sec = NULL;
368      if (r_symndx < symtab_hdr->sh_info)
369	{
370	  sym = local_syms + r_symndx;
371	  sec = local_sections[r_symndx];
372	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
373	}
374      else
375	{
376	  bfd_boolean unresolved_reloc, warned, ignored;
377
378	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
379				   r_symndx, symtab_hdr, sym_hashes,
380				   h, sec, relocation,
381				   unresolved_reloc, warned, ignored);
382	}
383
384      if (sec != NULL && discarded_section (sec))
385	{
386	  /* For relocs against symbols from removed linkonce sections,
387	     or sections discarded by a linker script, we just want the
388	     section contents cleared.  Avoid any special processing.  */
389	  reloc_howto_type *howto;
390	  howto = xc16x_reloc_type_lookup (input_bfd, r_type);
391	  RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
392					   rel, 1, relend, howto, 0, contents);
393	}
394
395      if (bfd_link_relocatable (info))
396	continue;
397
398      elf32_xc16x_final_link_relocate (r_type, input_bfd, output_bfd,
399				       input_section,
400				       contents, rel->r_offset,
401				       relocation, rel->r_addend,
402				       info, sec, h == NULL);
403    }
404
405  return TRUE;
406}
407
408
409static void
410elf32_xc16x_final_write_processing (bfd *abfd,
411				    bfd_boolean linker ATTRIBUTE_UNUSED)
412{
413  unsigned long val;
414
415  switch (bfd_get_mach (abfd))
416    {
417    default:
418    case bfd_mach_xc16x:
419      val = 0x1000;
420      break;
421
422    case bfd_mach_xc16xl:
423      val = 0x1001;
424      break;
425
426    case bfd_mach_xc16xs:
427      val = 0x1002;
428      break;
429    }
430
431  elf_elfheader (abfd)->e_flags |= val;
432}
433
434static unsigned long
435elf32_xc16x_mach (flagword flags)
436{
437  switch (flags)
438    {
439    case 0x1000:
440    default:
441      return bfd_mach_xc16x;
442
443    case 0x1001:
444      return bfd_mach_xc16xl;
445
446    case 0x1002:
447      return bfd_mach_xc16xs;
448    }
449}
450
451
452static bfd_boolean
453elf32_xc16x_object_p (bfd *abfd)
454{
455  bfd_default_set_arch_mach (abfd, bfd_arch_xc16x,
456			     elf32_xc16x_mach (elf_elfheader (abfd)->e_flags));
457  return TRUE;
458}
459
460
461#define ELF_ARCH		bfd_arch_xc16x
462#define ELF_MACHINE_CODE	EM_XC16X
463#define ELF_MAXPAGESIZE		0x100
464
465#define TARGET_LITTLE_SYM       xc16x_elf32_vec
466#define TARGET_LITTLE_NAME	"elf32-xc16x"
467#define elf_backend_final_write_processing	elf32_xc16x_final_write_processing
468#define elf_backend_object_p   		elf32_xc16x_object_p
469#define elf_backend_can_gc_sections	1
470#define bfd_elf32_bfd_reloc_type_lookup	xc16x_reloc_type_lookup
471#define bfd_elf32_bfd_reloc_name_lookup xc16x_reloc_name_lookup
472#define elf_info_to_howto		elf32_xc16x_info_to_howto
473#define elf_info_to_howto_rel		elf32_xc16x_info_to_howto
474#define elf_backend_relocate_section  	elf32_xc16x_relocate_section
475#define elf_backend_rela_normal		1
476
477#include "elf32-target.h"
478