1/* Infineon XC16X-specific support for 16-bit ELF.
2   Copyright 2006, 2007  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 "elf/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	 1,			/* size (0 = byte, 1 = short, 2 = long) */
36	 16,			/* bitsize */
37	 FALSE,			/* pc_relative */
38	 0,			/* bitpos */
39	 complain_overflow_bitfield, /* 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      bfd_reloc_status_type r;
362
363      /* This is a final link.  */
364      r_symndx = ELF32_R_SYM (rel->r_info);
365      r_type = ELF32_R_TYPE (rel->r_info);
366      h = NULL;
367      sym = NULL;
368      sec = NULL;
369      if (r_symndx < symtab_hdr->sh_info)
370	{
371	  sym = local_syms + r_symndx;
372	  sec = local_sections[r_symndx];
373	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
374	}
375      else
376	{
377	  bfd_boolean unresolved_reloc, warned;
378
379	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
380				   r_symndx, symtab_hdr, sym_hashes,
381				   h, sec, relocation,
382				   unresolved_reloc, warned);
383	}
384
385      if (sec != NULL && elf_discarded_section (sec))
386	{
387	  /* For relocs against symbols from removed linkonce sections,
388	     or sections discarded by a linker script, we just want the
389	     section contents zeroed.  Avoid any special processing.  */
390	  reloc_howto_type *howto;
391	  howto = xc16x_reloc_type_lookup (input_bfd, r_type);
392	  _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
393	  rel->r_info = 0;
394	  rel->r_addend = 0;
395	  continue;
396	}
397
398      if (info->relocatable)
399	continue;
400
401      r = elf32_xc16x_final_link_relocate (r_type, input_bfd, output_bfd,
402					   input_section,
403					   contents, rel->r_offset,
404					   relocation, rel->r_addend,
405					   info, sec, h == NULL);
406    }
407
408  return TRUE;
409}
410
411
412static void
413elf32_xc16x_final_write_processing (bfd *abfd,
414				    bfd_boolean linker ATTRIBUTE_UNUSED)
415{
416  unsigned long val;
417
418  switch (bfd_get_mach (abfd))
419    {
420    default:
421    case bfd_mach_xc16x:
422      val = 0x1000;
423      break;
424
425    case bfd_mach_xc16xl:
426      val = 0x1001;
427      break;
428
429    case bfd_mach_xc16xs:
430      val = 0x1002;
431      break;
432    }
433
434  elf_elfheader (abfd)->e_flags |= val;
435}
436
437static unsigned long
438elf32_xc16x_mach (flagword flags)
439{
440  switch (flags)
441    {
442    case 0x1000:
443    default:
444      return bfd_mach_xc16x;
445
446    case 0x1001:
447      return bfd_mach_xc16xl;
448
449    case 0x1002:
450      return bfd_mach_xc16xs;
451    }
452}
453
454
455static bfd_boolean
456elf32_xc16x_object_p (bfd *abfd)
457{
458  bfd_default_set_arch_mach (abfd, bfd_arch_xc16x,
459			     elf32_xc16x_mach (elf_elfheader (abfd)->e_flags));
460  return TRUE;
461}
462
463
464#define ELF_ARCH		bfd_arch_xc16x
465#define ELF_MACHINE_CODE	EM_XC16X
466#define ELF_MAXPAGESIZE		0x100
467
468#define TARGET_LITTLE_SYM       bfd_elf32_xc16x_vec
469#define TARGET_LITTLE_NAME	"elf32-xc16x"
470#define elf_backend_final_write_processing	elf32_xc16x_final_write_processing
471#define elf_backend_object_p   		elf32_xc16x_object_p
472#define elf_backend_can_gc_sections	1
473#define bfd_elf32_bfd_reloc_type_lookup	xc16x_reloc_type_lookup
474#define bfd_elf32_bfd_reloc_name_lookup xc16x_reloc_name_lookup
475#define elf_info_to_howto		elf32_xc16x_info_to_howto
476#define elf_info_to_howto_rel		elf32_xc16x_info_to_howto
477#define elf_backend_relocate_section  	elf32_xc16x_relocate_section
478#define elf_backend_rela_normal		1
479
480#include "elf32-target.h"
481