Home | History | Annotate | Download | only in bfd
      1 /* Infineon XC16X-specific support for 16-bit ELF.
      2    Copyright (C) 2006-2014 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 
     30 static 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 
    173 struct xc16x_reloc_map
    174 {
    175   bfd_reloc_code_real_type bfd_reloc_val;
    176   unsigned int xc16x_reloc_val;
    177 };
    178 
    179 static 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 
    196 static reloc_howto_type *
    197 xc16x_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 
    209 static reloc_howto_type *
    210 xc16x_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 
    228 static void
    229 elf32_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 
    245 static bfd_reloc_status_type
    246 elf32_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 
    334 static bfd_boolean
    335 elf32_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 (info->relocatable)
    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 
    409 static void
    410 elf32_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 
    434 static unsigned long
    435 elf32_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 
    452 static bfd_boolean
    453 elf32_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