Back to index

cell-binutils  2.17cvs20070401
elf32-xc16x.c
Go to the documentation of this file.
00001 /* Infineon XC16X-specific support for 16-bit ELF.
00002    Copyright 2006, 2007  Free Software Foundation, Inc.
00003    Contributed by KPIT Cummins Infosystems 
00004 
00005    This file is part of BFD, the Binary File Descriptor library.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 #include "bfd.h"
00022 #include "sysdep.h"
00023 #include "libbfd.h"
00024 #include "elf-bfd.h"
00025 #include "elf/xc16x.h"
00026 #include "elf/dwarf2.h"
00027 #include "libiberty.h"
00028 
00029 static reloc_howto_type xc16x_elf_howto_table [] =
00030 {
00031   /* This reloc does nothing.  */
00032   HOWTO (R_XC16X_NONE,             /* type */
00033         0,                  /* rightshift */
00034         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00035         16,                 /* bitsize */
00036         FALSE,                     /* pc_relative */
00037         0,                  /* bitpos */
00038         complain_overflow_bitfield, /* complain_on_overflow */
00039         bfd_elf_generic_reloc,     /* special_function */
00040         "R_XC16X_NONE",     /* name */
00041         FALSE,                     /* partial_inplace */
00042         0,                  /* src_mask */
00043         0,                  /* dst_mask */
00044         FALSE),             /* pcrel_offset */
00045 
00046   /* An 8 bit absolute relocation.  */
00047   HOWTO (R_XC16X_ABS_8,            /* type */
00048         0,                  /* rightshift */
00049         0,                  /* size (0 = byte, 1 = short, 2 = long) */
00050         8,                  /* bitsize */
00051         FALSE,                     /* pc_relative */
00052         8,                  /* bitpos */
00053         complain_overflow_bitfield, /* complain_on_overflow */
00054         bfd_elf_generic_reloc,     /* special_function */
00055         "R_XC16X_ABS_8",    /* name */
00056         TRUE,               /* partial_inplace */
00057         0x0000,             /* src_mask */
00058         0x00ff,             /* dst_mask */
00059         FALSE),             /* pcrel_offset */
00060 
00061   /* A 16 bit absolute relocation.  */
00062   HOWTO (R_XC16X_ABS_16,    /* type */
00063         0,                  /* rightshift */
00064         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00065         16,                 /* bitsize */
00066         FALSE,                     /* pc_relative */
00067         0,                  /* bitpos */
00068         complain_overflow_dont, /* complain_on_overflow */
00069         bfd_elf_generic_reloc,     /* special_function */
00070         "R_XC16X_ABS_16",   /* name */
00071         TRUE,               /* partial_inplace */
00072         0x00000000,         /* src_mask */
00073         0x0000ffff,         /* dst_mask */
00074         FALSE),             /* pcrel_offset */
00075 
00076   HOWTO (R_XC16X_ABS_32,    /* type */
00077         0,                  /* rightshift */
00078         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00079         32,                 /* bitsize */
00080         FALSE,                     /* pc_relative */
00081         0,                  /* bitpos */
00082         complain_overflow_bitfield, /* complain_on_overflow */
00083         bfd_elf_generic_reloc,     /* special_function */
00084         "R_XC16X_ABS_32",   /* name */
00085         TRUE,               /* partial_inplace */
00086         0x00000000,         /* src_mask */
00087         0xffffffff,         /* dst_mask */
00088         FALSE),             /* pcrel_offset */
00089 
00090 
00091   /* A PC relative 8 bit relocation.  */
00092   HOWTO (R_XC16X_8_PCREL,   /* type */
00093         0,                  /* rightshift */
00094         0,                  /* size (0 = byte, 1 = short, 2 = long) */
00095         8,                  /* bitsize */
00096         TRUE,               /* pc_relative */
00097         8,                  /* bitpos */
00098         complain_overflow_signed, /* complain_on_overflow */
00099         bfd_elf_generic_reloc, /* special_function */
00100         "R_XC16X_8_PCREL",  /* name */
00101         FALSE,                     /* partial_inplace */
00102         0x0000,             /* src_mask */
00103         0x00ff,             /* dst_mask */
00104         TRUE),              /* pcrel_offset */
00105 
00106   /* Relocation regarding page number.  */
00107     HOWTO (R_XC16X_PAG,     /* type */
00108         0,                  /* rightshift */
00109         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00110         16,                 /* bitsize */
00111         FALSE,                     /* pc_relative */
00112         0,                  /* bitpos */
00113         complain_overflow_signed, /* complain_on_overflow */
00114         bfd_elf_generic_reloc, /* special_function */
00115         "R_XC16X_PAG",      /* name */
00116         TRUE,               /* partial_inplace */
00117         0x00000000,         /* src_mask */
00118         0x0000ffff,         /* dst_mask */
00119         FALSE),             /* pcrel_offset */
00120 
00121 
00122   /* Relocation regarding page number.  */
00123       HOWTO (R_XC16X_POF,   /* type */
00124         0,                  /* rightshift */
00125         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00126         16,                 /* bitsize */
00127         FALSE,                     /* pc_relative */
00128         0,                  /* bitpos  */
00129         complain_overflow_signed, /* complain_on_overflow  */
00130         bfd_elf_generic_reloc, /* special_function  */
00131         "R_XC16X_POF",      /* name  */
00132         TRUE,               /* partial_inplace  */
00133         0x00000000,         /* src_mask  */
00134         0x0000ffff,         /* dst_mask  */
00135         FALSE),             /* pcrel_offset  */
00136 
00137 
00138   /* Relocation regarding segment number.   */
00139       HOWTO (R_XC16X_SEG,   /* type  */
00140         0,                  /* rightshift  */
00141         1,                  /* size (0 = byte, 1 = short, 2 = long)  */
00142         16,                 /* bitsize  */
00143         FALSE,                     /* pc_relative  */
00144         0,                  /* bitpos  */
00145         complain_overflow_signed, /* complain_on_overflow  */
00146         bfd_elf_generic_reloc, /* special_function  */
00147         "R_XC16X_SEG",      /* name  */
00148         TRUE,               /* partial_inplace  */
00149         0x00000000,         /* src_mask  */
00150         0x0000ffff,         /* dst_mask  */
00151         FALSE),             /* pcrel_offset  */
00152 
00153   /* Relocation regarding segment offset.  */
00154       HOWTO (R_XC16X_SOF,   /* type  */
00155         0,                  /* rightshift  */
00156         1,                  /* size (0 = byte, 1 = short, 2 = long)  */
00157         16,                 /* bitsize  */
00158         FALSE,                     /* pc_relative  */
00159         0,                  /* bitpos  */
00160         complain_overflow_signed, /* complain_on_overflow  */
00161         bfd_elf_generic_reloc, /* special_function  */
00162         "R_XC16X_SOF",      /* name */
00163         TRUE,               /* partial_inplace  */
00164         0x00000000,         /* src_mask  */
00165         0x0000ffff,         /* dst_mask  */
00166         FALSE)                     /* pcrel_offset  */
00167 };
00168 
00169 
00170 /* Map BFD reloc types to XC16X ELF reloc types.  */
00171 
00172 struct xc16x_reloc_map
00173 {
00174   bfd_reloc_code_real_type bfd_reloc_val;
00175   unsigned int xc16x_reloc_val;
00176 };
00177 
00178 static const struct xc16x_reloc_map xc16x_reloc_map [] =
00179 {
00180   { BFD_RELOC_NONE,           R_XC16X_NONE },
00181   { BFD_RELOC_8,              R_XC16X_ABS_8 },
00182   { BFD_RELOC_16,             R_XC16X_ABS_16 },
00183   { BFD_RELOC_32,             R_XC16X_ABS_32 },
00184   { BFD_RELOC_8_PCREL,        R_XC16X_8_PCREL },
00185   { BFD_RELOC_XC16X_PAG,      R_XC16X_PAG},
00186   { BFD_RELOC_XC16X_POF,      R_XC16X_POF},
00187   { BFD_RELOC_XC16X_SEG,      R_XC16X_SEG},
00188   { BFD_RELOC_XC16X_SOF,      R_XC16X_SOF},
00189 };
00190 
00191 
00192 /* This function is used to search for correct relocation type from
00193    howto structure.  */
00194 
00195 static reloc_howto_type *
00196 xc16x_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00197                       bfd_reloc_code_real_type code)
00198 {
00199   unsigned int i;
00200 
00201   for (i = ARRAY_SIZE (xc16x_reloc_map); --i;)
00202     if (xc16x_reloc_map [i].bfd_reloc_val == code)
00203       return & xc16x_elf_howto_table [xc16x_reloc_map[i].xc16x_reloc_val];
00204 
00205   return NULL;
00206 }
00207 
00208 static reloc_howto_type *
00209 xc16x_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00210                       const char *r_name)
00211 {
00212   unsigned int i;
00213 
00214   for (i = 0;
00215        i < sizeof (xc16x_elf_howto_table) / sizeof (xc16x_elf_howto_table[0]);
00216        i++)
00217     if (xc16x_elf_howto_table[i].name != NULL
00218        && strcasecmp (xc16x_elf_howto_table[i].name, r_name) == 0)
00219       return &xc16x_elf_howto_table[i];
00220 
00221   return NULL;
00222 }
00223 
00224 /* For a particular operand this function is
00225    called to finalise the type of relocation.  */
00226 
00227 static void
00228 elf32_xc16x_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc,
00229                         Elf_Internal_Rela *elf_reloc)
00230 {
00231   unsigned int r;
00232   unsigned int i;
00233 
00234   r = ELF32_R_TYPE (elf_reloc->r_info);
00235   for (i = 0; i < ARRAY_SIZE (xc16x_elf_howto_table); i++)
00236     if (xc16x_elf_howto_table[i].type == r)
00237       {
00238        bfd_reloc->howto = &xc16x_elf_howto_table[i];
00239        return;
00240       }
00241   abort ();
00242 }
00243 
00244 static bfd_reloc_status_type
00245 elf32_xc16x_final_link_relocate (unsigned long r_type,
00246                              bfd *input_bfd,
00247                              bfd *output_bfd ATTRIBUTE_UNUSED,
00248                              asection *input_section ATTRIBUTE_UNUSED,
00249                              bfd_byte *contents,
00250                              bfd_vma offset,
00251                              bfd_vma value,
00252                              bfd_vma addend,
00253                              struct bfd_link_info *info ATTRIBUTE_UNUSED,
00254                              asection *sym_sec ATTRIBUTE_UNUSED,
00255                              int is_local ATTRIBUTE_UNUSED)
00256 {
00257   bfd_byte *hit_data = contents + offset;
00258   bfd_vma val1;
00259 
00260   switch (r_type)
00261     {
00262     case R_XC16X_NONE:
00263       return bfd_reloc_ok;
00264 
00265     case R_XC16X_ABS_16:
00266       value += addend;
00267       bfd_put_16 (input_bfd, value, hit_data);
00268       return bfd_reloc_ok;
00269 
00270     case R_XC16X_8_PCREL:
00271       bfd_put_8 (input_bfd, value, hit_data);
00272       return bfd_reloc_ok;
00273 
00274       /* Following case is to find page number from actual
00275         address for this divide value by 16k i.e. page size.  */
00276 
00277     case R_XC16X_PAG:
00278       value += addend;
00279       value /= 0x4000;
00280       bfd_put_16 (input_bfd, value, hit_data);
00281       return bfd_reloc_ok;
00282 
00283       /* Following case is to find page offset from actual address
00284         for this take modulo of value by 16k i.e. page size.  */
00285 
00286     case R_XC16X_POF:
00287       value += addend;
00288       value %= 0x4000;
00289       bfd_put_16 (input_bfd, value, hit_data);
00290       return bfd_reloc_ok;
00291 
00292       /* Following case is to find segment number from actual
00293         address for this divide value by 64k i.e. segment size.  */
00294 
00295     case R_XC16X_SEG:
00296       value += addend;
00297       value /= 0x10000;
00298       bfd_put_16 (input_bfd, value, hit_data);
00299       return bfd_reloc_ok;
00300 
00301       /* Following case is to find segment offset from actual address
00302         for this take modulo of value by 64k i.e. segment size.  */
00303 
00304     case R_XC16X_SOF:
00305       value += addend;
00306       value %= 0x10000;
00307       bfd_put_16 (input_bfd, value, hit_data);
00308       return bfd_reloc_ok;
00309 
00310     case R_XC16X_ABS_32:
00311       if (!strstr (input_section->name,".debug"))
00312        {
00313          value += addend;
00314          val1 = value;
00315          value %= 0x4000;
00316          val1 /= 0x4000;
00317          val1 = val1 << 16;
00318          value += val1;
00319          bfd_put_32 (input_bfd, value, hit_data);
00320        }
00321       else
00322        {
00323          value += addend;
00324          bfd_put_32 (input_bfd, value, hit_data);
00325        }
00326       return bfd_reloc_ok;
00327 
00328     default:
00329       return bfd_reloc_notsupported;
00330     }
00331 }
00332 
00333 static bfd_boolean
00334 elf32_xc16x_relocate_section (bfd *output_bfd,
00335                            struct bfd_link_info *info,
00336                            bfd *input_bfd,
00337                            asection *input_section,
00338                            bfd_byte *contents,
00339                            Elf_Internal_Rela *relocs,
00340                            Elf_Internal_Sym *local_syms,
00341                            asection **local_sections)
00342 {
00343   Elf_Internal_Shdr *symtab_hdr;
00344   struct elf_link_hash_entry **sym_hashes;
00345   Elf_Internal_Rela *rel, *relend;
00346 
00347   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
00348   sym_hashes = elf_sym_hashes (input_bfd);
00349 
00350   rel = relocs;
00351   relend = relocs + input_section->reloc_count;
00352   for (; rel < relend; rel++)
00353     {
00354       unsigned int r_type;
00355       unsigned long r_symndx;
00356       Elf_Internal_Sym *sym;
00357       asection *sec;
00358       struct elf_link_hash_entry *h;
00359       bfd_vma relocation;
00360       bfd_reloc_status_type r;
00361 
00362       /* This is a final link.  */
00363       r_symndx = ELF32_R_SYM (rel->r_info);
00364       r_type = ELF32_R_TYPE (rel->r_info);
00365       h = NULL;
00366       sym = NULL;
00367       sec = NULL;
00368       if (r_symndx < symtab_hdr->sh_info)
00369        {
00370          sym = local_syms + r_symndx;
00371          sec = local_sections[r_symndx];
00372          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
00373        }
00374       else
00375        {
00376          bfd_boolean unresolved_reloc, warned;
00377 
00378          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
00379                                r_symndx, symtab_hdr, sym_hashes,
00380                                h, sec, relocation,
00381                                unresolved_reloc, warned);
00382        }
00383 
00384       if (sec != NULL && elf_discarded_section (sec))
00385        {
00386          /* For relocs against symbols from removed linkonce sections,
00387             or sections discarded by a linker script, we just want the
00388             section contents zeroed.  Avoid any special processing.  */
00389          reloc_howto_type *howto;
00390          howto = xc16x_reloc_type_lookup (input_bfd, r_type);
00391          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
00392          rel->r_info = 0;
00393          rel->r_addend = 0;
00394          continue;
00395        }
00396 
00397       if (info->relocatable)
00398        continue;
00399 
00400       r = elf32_xc16x_final_link_relocate (r_type, input_bfd, output_bfd,
00401                                       input_section,
00402                                       contents, rel->r_offset,
00403                                       relocation, rel->r_addend,
00404                                       info, sec, h == NULL);
00405     }
00406 
00407   return TRUE;
00408 }
00409 
00410 
00411 static void
00412 elf32_xc16x_final_write_processing (bfd *abfd,
00413                                 bfd_boolean linker ATTRIBUTE_UNUSED)
00414 {
00415   unsigned long val;
00416 
00417   switch (bfd_get_mach (abfd))
00418     {
00419     default:
00420     case bfd_mach_xc16x:
00421       val = 0x1000;
00422       break;
00423 
00424     case bfd_mach_xc16xl:
00425       val = 0x1001;
00426       break;
00427 
00428     case bfd_mach_xc16xs:
00429       val = 0x1002;
00430       break;
00431     }
00432 
00433   elf_elfheader (abfd)->e_flags |= val;
00434 }
00435 
00436 static unsigned long
00437 elf32_xc16x_mach (flagword flags)
00438 {  
00439   switch (flags)
00440     {
00441     case 0x1000:
00442     default: 
00443       return bfd_mach_xc16x;
00444 
00445     case 0x1001:
00446       return bfd_mach_xc16xl;
00447 
00448     case 0x1002:
00449       return bfd_mach_xc16xs;
00450     }
00451 }
00452 
00453 
00454 static bfd_boolean
00455 elf32_xc16x_object_p (bfd *abfd)
00456 {
00457   bfd_default_set_arch_mach (abfd, bfd_arch_xc16x,
00458                           elf32_xc16x_mach (elf_elfheader (abfd)->e_flags));
00459   return TRUE;
00460 }
00461 
00462 
00463 #define ELF_ARCH            bfd_arch_xc16x
00464 #define ELF_MACHINE_CODE    EM_XC16X
00465 #define ELF_MAXPAGESIZE            0x100
00466 
00467 #define TARGET_LITTLE_SYM       bfd_elf32_xc16x_vec
00468 #define TARGET_LITTLE_NAME  "elf32-xc16x"
00469 #define elf_backend_final_write_processing       elf32_xc16x_final_write_processing
00470 #define elf_backend_object_p              elf32_xc16x_object_p
00471 #define elf_backend_can_gc_sections       1
00472 #define bfd_elf32_bfd_reloc_type_lookup   xc16x_reloc_type_lookup
00473 #define bfd_elf32_bfd_reloc_name_lookup xc16x_reloc_name_lookup
00474 #define elf_info_to_howto          elf32_xc16x_info_to_howto
00475 #define elf_info_to_howto_rel             elf32_xc16x_info_to_howto
00476 #define elf_backend_relocate_section      elf32_xc16x_relocate_section
00477 #define elf_backend_rela_normal           1
00478 
00479 #include "elf32-target.h"