Home | History | Annotate | Line # | Download | only in bfd
elf32-fr30.c revision 1.1.1.5
      1 /* FR30-specific support for 32-bit ELF.
      2    Copyright (C) 1998-2017 Free Software Foundation, Inc.
      3 
      4    This file is part of BFD, the Binary File Descriptor library.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program; if not, write to the Free Software
     18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19    MA 02110-1301, USA.  */
     20 
     21 #include "sysdep.h"
     22 #include "bfd.h"
     23 #include "libbfd.h"
     24 #include "elf-bfd.h"
     25 #include "elf/fr30.h"
     26 
     27 /* Forward declarations.  */
     28 static bfd_reloc_status_type
     29 fr30_elf_i20_reloc (bfd *, arelent *, asymbol *, void * data,
     30 		    asection *, bfd *, char **error_message);
     31 static bfd_reloc_status_type
     32 fr30_elf_i32_reloc (bfd *, arelent *, asymbol *, void *,
     33 		    asection *, bfd *, char **);
     34 
     35 static reloc_howto_type fr30_elf_howto_table [] =
     36 {
     37   /* This reloc does nothing.  */
     38   HOWTO (R_FR30_NONE,		/* type */
     39 	 0,			/* rightshift */
     40 	 3,			/* size (0 = byte, 1 = short, 2 = long) */
     41 	 0,			/* bitsize */
     42 	 FALSE,			/* pc_relative */
     43 	 0,			/* bitpos */
     44 	 complain_overflow_dont, /* complain_on_overflow */
     45 	 bfd_elf_generic_reloc,	/* special_function */
     46 	 "R_FR30_NONE",		/* name */
     47 	 FALSE,			/* partial_inplace */
     48 	 0,			/* src_mask */
     49 	 0,			/* dst_mask */
     50 	 FALSE),		/* pcrel_offset */
     51 
     52   /* An 8 bit absolute relocation.  */
     53   HOWTO (R_FR30_8,		/* type */
     54 	 0,			/* rightshift */
     55 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
     56 	 8,			/* bitsize */
     57 	 FALSE,			/* pc_relative */
     58 	 4,			/* bitpos */
     59 	 complain_overflow_bitfield, /* complain_on_overflow */
     60 	 bfd_elf_generic_reloc,	/* special_function */
     61 	 "R_FR30_8",		/* name */
     62 	 FALSE,			/* partial_inplace */
     63 	 0x0000,		/* src_mask */
     64 	 0x0ff0,		/* dst_mask */
     65 	 FALSE),		/* pcrel_offset */
     66 
     67   /* A 20 bit absolute relocation.  */
     68   HOWTO (R_FR30_20,		/* type */
     69 	 0,			/* rightshift */
     70 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
     71 	 20,			/* bitsize */
     72 	 FALSE,			/* pc_relative */
     73 	 0,			/* bitpos */
     74 	 complain_overflow_bitfield, /* complain_on_overflow */
     75 	 fr30_elf_i20_reloc,	/* special_function */
     76 	 "R_FR30_20",		/* name */
     77 	 FALSE,			/* partial_inplace */
     78 	 0x00000000,		/* src_mask */
     79 	 0x00f0ffff,		/* dst_mask */
     80 	 FALSE),		/* pcrel_offset */
     81 
     82   /* A 32 bit absolute relocation.  */
     83   HOWTO (R_FR30_32,		/* type */
     84 	 0,			/* rightshift */
     85 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
     86 	 32,			/* bitsize */
     87 	 FALSE,			/* pc_relative */
     88 	 0,			/* bitpos */
     89 	 complain_overflow_bitfield, /* complain_on_overflow */
     90 	 bfd_elf_generic_reloc,	/* special_function */
     91 	 "R_FR30_32",		/* name */
     92 	 FALSE,			/* partial_inplace */
     93 	 0x00000000,		/* src_mask */
     94 	 0xffffffff,		/* dst_mask */
     95 	 FALSE),		/* pcrel_offset */
     96 
     97   /* A 32 bit into 48 bits absolute relocation.  */
     98   HOWTO (R_FR30_48,		/* type */
     99 	 0,			/* rightshift */
    100 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    101 	 32,			/* bitsize */
    102 	 FALSE,			/* pc_relative */
    103 	 0,			/* bitpos */
    104 	 complain_overflow_bitfield, /* complain_on_overflow */
    105 	 fr30_elf_i32_reloc,	/* special_function */
    106 	 "R_FR30_48",		/* name */
    107 	 FALSE,			/* partial_inplace */
    108 	 0x00000000,		/* src_mask */
    109 	 0xffffffff,		/* dst_mask */
    110 	 FALSE),		/* pcrel_offset */
    111 
    112   /* A 6 bit absolute relocation.  */
    113   HOWTO (R_FR30_6_IN_4,		/* type */
    114 	 2,			/* rightshift */
    115 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    116 	 6,			/* bitsize */
    117 	 FALSE,			/* pc_relative */
    118 	 4,			/* bitpos */
    119 	 complain_overflow_unsigned, /* complain_on_overflow */
    120 	 bfd_elf_generic_reloc,	/* special_function */
    121 	 "R_FR30_6_IN_4",	/* name */
    122 	 FALSE,			/* partial_inplace */
    123 	 0x0000,		/* src_mask */
    124 	 0x00f0,		/* dst_mask */
    125 	 FALSE),		/* pcrel_offset */
    126 
    127   /* An 8 bit absolute relocation.  */
    128   HOWTO (R_FR30_8_IN_8,		/* type */
    129 	 0,			/* rightshift */
    130 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    131 	 8,			/* bitsize */
    132 	 FALSE,			/* pc_relative */
    133 	 4,			/* bitpos */
    134 	 complain_overflow_signed, /* complain_on_overflow */
    135 	 bfd_elf_generic_reloc,/* special_function */
    136 	 "R_FR30_8_IN_8",	/* name */
    137 	 FALSE,			/* partial_inplace */
    138 	 0x0000,		/* src_mask */
    139 	 0x0ff0,		/* dst_mask */
    140 	 FALSE),		/* pcrel_offset */
    141 
    142   /* A 9 bit absolute relocation.  */
    143   HOWTO (R_FR30_9_IN_8,		/* type */
    144 	 1,			/* rightshift */
    145 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    146 	 9,			/* bitsize */
    147 	 FALSE,			/* pc_relative */
    148 	 4,			/* bitpos */
    149 	 complain_overflow_signed, /* complain_on_overflow */
    150 	 bfd_elf_generic_reloc,/* special_function */
    151 	 "R_FR30_9_IN_8",	/* name */
    152 	 FALSE,			/* partial_inplace */
    153 	 0x0000,		/* src_mask */
    154 	 0x0ff0,		/* dst_mask */
    155 	 FALSE),		/* pcrel_offset */
    156 
    157   /* A 10 bit absolute relocation.  */
    158   HOWTO (R_FR30_10_IN_8,	/* type */
    159 	 2,			/* rightshift */
    160 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    161 	 10,			/* bitsize */
    162 	 FALSE,			/* pc_relative */
    163 	 4,			/* bitpos */
    164 	 complain_overflow_signed, /* complain_on_overflow */
    165 	 bfd_elf_generic_reloc,/* special_function */
    166 	 "R_FR30_10_IN_8",	/* name */
    167 	 FALSE,			/* partial_inplace */
    168 	 0x0000,		/* src_mask */
    169 	 0x0ff0,		/* dst_mask */
    170 	 FALSE),		/* pcrel_offset */
    171 
    172   /* A PC relative 9 bit relocation, right shifted by 1.  */
    173   HOWTO (R_FR30_9_PCREL,	/* type */
    174 	 1,			/* rightshift */
    175 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    176 	 9,			/* bitsize */
    177 	 TRUE,			/* pc_relative */
    178 	 0,			/* bitpos */
    179 	 complain_overflow_signed, /* complain_on_overflow */
    180 	 bfd_elf_generic_reloc, /* special_function */
    181 	 "R_FR30_9_PCREL",	/* name */
    182 	 FALSE,			/* partial_inplace */
    183 	 0x0000,		/* src_mask */
    184 	 0x00ff,		/* dst_mask */
    185 	 FALSE),		/* pcrel_offset */
    186 
    187   /* A PC relative 12 bit relocation, right shifted by 1.  */
    188   HOWTO (R_FR30_12_PCREL,	/* type */
    189 	 1,			/* rightshift */
    190 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    191 	 12,			/* bitsize */
    192 	 TRUE,			/* pc_relative */
    193 	 0,			/* bitpos */
    194 	 complain_overflow_signed, /* complain_on_overflow */
    195 	 bfd_elf_generic_reloc, /* special_function */
    196 	 "R_FR30_12_PCREL",	/* name */
    197 	 FALSE,			/* partial_inplace */
    198 	 0x0000,		/* src_mask */
    199 	 0x07ff,		/* dst_mask */
    200 	 FALSE),		/* pcrel_offset */
    201   /* GNU extension to record C++ vtable hierarchy */
    202   HOWTO (R_FR30_GNU_VTINHERIT, /* type */
    203          0,                     /* rightshift */
    204          2,                     /* size (0 = byte, 1 = short, 2 = long) */
    205          0,                     /* bitsize */
    206          FALSE,                 /* pc_relative */
    207          0,                     /* bitpos */
    208          complain_overflow_dont, /* complain_on_overflow */
    209          NULL,                  /* special_function */
    210          "R_FR30_GNU_VTINHERIT", /* name */
    211          FALSE,                 /* partial_inplace */
    212          0,                     /* src_mask */
    213          0,                     /* dst_mask */
    214          FALSE),                /* pcrel_offset */
    215 
    216   /* GNU extension to record C++ vtable member usage */
    217   HOWTO (R_FR30_GNU_VTENTRY,     /* type */
    218          0,                     /* rightshift */
    219          2,                     /* size (0 = byte, 1 = short, 2 = long) */
    220          0,                     /* bitsize */
    221          FALSE,                 /* pc_relative */
    222          0,                     /* bitpos */
    223          complain_overflow_dont, /* complain_on_overflow */
    224          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
    225          "R_FR30_GNU_VTENTRY",   /* name */
    226          FALSE,                 /* partial_inplace */
    227          0,                     /* src_mask */
    228          0,                     /* dst_mask */
    229          FALSE),                /* pcrel_offset */
    230 };
    231 
    232 /* Utility to actually perform an R_FR30_20 reloc.  */
    234 
    235 static bfd_reloc_status_type
    236 fr30_elf_i20_reloc (bfd *abfd,
    237 		    arelent *reloc_entry,
    238 		    asymbol *symbol,
    239 		    void * data,
    240 		    asection *input_section,
    241 		    bfd *output_bfd,
    242 		    char **error_message ATTRIBUTE_UNUSED)
    243 {
    244   bfd_vma relocation;
    245   unsigned long x;
    246 
    247   /* This part is from bfd_elf_generic_reloc.  */
    248   if (output_bfd != (bfd *) NULL
    249       && (symbol->flags & BSF_SECTION_SYM) == 0
    250       && (! reloc_entry->howto->partial_inplace
    251 	  || reloc_entry->addend == 0))
    252     {
    253       reloc_entry->address += input_section->output_offset;
    254       return bfd_reloc_ok;
    255     }
    256 
    257   if (output_bfd != NULL)
    258     /* FIXME: See bfd_perform_relocation.  Is this right?  */
    259     return bfd_reloc_ok;
    260 
    261   relocation =
    262     symbol->value
    263     + symbol->section->output_section->vma
    264     + symbol->section->output_offset
    265     + reloc_entry->addend;
    266 
    267   if (relocation > (((bfd_vma) 1 << 20) - 1))
    268     return bfd_reloc_overflow;
    269 
    270   x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
    271   x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
    272   bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
    273 
    274   return bfd_reloc_ok;
    275 }
    276 
    277 /* Utility to actually perform a R_FR30_48 reloc.  */
    279 
    280 static bfd_reloc_status_type
    281 fr30_elf_i32_reloc (bfd *abfd,
    282 		    arelent *reloc_entry,
    283 		    asymbol *symbol,
    284 		    void * data,
    285 		    asection *input_section,
    286 		    bfd *output_bfd,
    287 		    char **error_message ATTRIBUTE_UNUSED)
    288 {
    289   bfd_vma relocation;
    290 
    291   /* This part is from bfd_elf_generic_reloc.  */
    292   if (output_bfd != (bfd *) NULL
    293       && (symbol->flags & BSF_SECTION_SYM) == 0
    294       && (! reloc_entry->howto->partial_inplace
    295 	  || reloc_entry->addend == 0))
    296     {
    297       reloc_entry->address += input_section->output_offset;
    298       return bfd_reloc_ok;
    299     }
    300 
    301   if (output_bfd != NULL)
    302     /* FIXME: See bfd_perform_relocation.  Is this right?  */
    303     return bfd_reloc_ok;
    304 
    305   relocation =
    306     symbol->value
    307     + symbol->section->output_section->vma
    308     + symbol->section->output_offset
    309     + reloc_entry->addend;
    310 
    311   bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
    312 
    313   return bfd_reloc_ok;
    314 }
    315 
    316 /* Map BFD reloc types to FR30 ELF reloc types.  */
    318 
    319 struct fr30_reloc_map
    320 {
    321   bfd_reloc_code_real_type bfd_reloc_val;
    322   unsigned int fr30_reloc_val;
    323 };
    324 
    325 static const struct fr30_reloc_map fr30_reloc_map [] =
    326 {
    327   { BFD_RELOC_NONE,           R_FR30_NONE },
    328   { BFD_RELOC_8,              R_FR30_8 },
    329   { BFD_RELOC_FR30_20,        R_FR30_20 },
    330   { BFD_RELOC_32,             R_FR30_32 },
    331   { BFD_RELOC_FR30_48,        R_FR30_48 },
    332   { BFD_RELOC_FR30_6_IN_4,    R_FR30_6_IN_4 },
    333   { BFD_RELOC_FR30_8_IN_8,    R_FR30_8_IN_8 },
    334   { BFD_RELOC_FR30_9_IN_8,    R_FR30_9_IN_8 },
    335   { BFD_RELOC_FR30_10_IN_8,   R_FR30_10_IN_8 },
    336   { BFD_RELOC_FR30_9_PCREL,   R_FR30_9_PCREL },
    337   { BFD_RELOC_FR30_12_PCREL,  R_FR30_12_PCREL },
    338   { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
    339   { BFD_RELOC_VTABLE_ENTRY,   R_FR30_GNU_VTENTRY },
    340 };
    341 
    342 static reloc_howto_type *
    343 fr30_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    344 			bfd_reloc_code_real_type code)
    345 {
    346   unsigned int i;
    347 
    348   for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
    349        i--;)
    350     if (fr30_reloc_map [i].bfd_reloc_val == code)
    351       return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
    352 
    353   return NULL;
    354 }
    355 
    356 static reloc_howto_type *
    357 fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
    358 {
    359   unsigned int i;
    360 
    361   for (i = 0;
    362        i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
    363        i++)
    364     if (fr30_elf_howto_table[i].name != NULL
    365 	&& strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
    366       return &fr30_elf_howto_table[i];
    367 
    368   return NULL;
    369 }
    370 
    371 /* Set the howto pointer for an FR30 ELF reloc.  */
    372 
    373 static void
    374 fr30_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
    375 			 arelent *cache_ptr,
    376 			 Elf_Internal_Rela *dst)
    377 {
    378   unsigned int r_type;
    379 
    380   r_type = ELF32_R_TYPE (dst->r_info);
    381   if (r_type >= (unsigned int) R_FR30_max)
    382     {
    383       /* xgettext:c-format */
    384       _bfd_error_handler (_("%B: invalid FR30 reloc number: %d"), abfd, r_type);
    385       r_type = 0;
    386     }
    387   cache_ptr->howto = & fr30_elf_howto_table [r_type];
    388 }
    389 
    390 /* Perform a single relocation.  By default we use the standard BFD
    392    routines, but a few relocs, we have to do them ourselves.  */
    393 
    394 static bfd_reloc_status_type
    395 fr30_final_link_relocate (reloc_howto_type *howto,
    396 			  bfd *input_bfd,
    397 			  asection *input_section,
    398 			  bfd_byte *contents,
    399 			  Elf_Internal_Rela *rel,
    400 			  bfd_vma relocation)
    401 {
    402   bfd_reloc_status_type r = bfd_reloc_ok;
    403   bfd_vma x;
    404   bfd_signed_vma srel;
    405 
    406   switch (howto->type)
    407     {
    408     case R_FR30_20:
    409       contents   += rel->r_offset;
    410       relocation += rel->r_addend;
    411 
    412       if (relocation > ((1 << 20) - 1))
    413 	return bfd_reloc_overflow;
    414 
    415       x = bfd_get_32 (input_bfd, contents);
    416       x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
    417       bfd_put_32 (input_bfd, x, contents);
    418       break;
    419 
    420     case R_FR30_48:
    421       contents   += rel->r_offset + 2;
    422       relocation += rel->r_addend;
    423       bfd_put_32 (input_bfd, relocation, contents);
    424       break;
    425 
    426     case R_FR30_9_PCREL:
    427       contents   += rel->r_offset + 1;
    428       srel = (bfd_signed_vma) relocation;
    429       srel += rel->r_addend;
    430       srel -= rel->r_offset;
    431       srel -= 2;  /* Branch instructions add 2 to the PC...  */
    432       srel -= (input_section->output_section->vma +
    433 		     input_section->output_offset);
    434 
    435       if (srel & 1)
    436 	return bfd_reloc_outofrange;
    437       if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
    438 	return bfd_reloc_overflow;
    439 
    440       bfd_put_8 (input_bfd, srel >> 1, contents);
    441       break;
    442 
    443     case R_FR30_12_PCREL:
    444       contents   += rel->r_offset;
    445       srel = (bfd_signed_vma) relocation;
    446       srel += rel->r_addend;
    447       srel -= rel->r_offset;
    448       srel -= 2; /* Branch instructions add 2 to the PC...  */
    449       srel -= (input_section->output_section->vma +
    450 		     input_section->output_offset);
    451 
    452       if (srel & 1)
    453 	return bfd_reloc_outofrange;
    454       if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
    455 	  return bfd_reloc_overflow;
    456 
    457       x = bfd_get_16 (input_bfd, contents);
    458       x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
    459       bfd_put_16 (input_bfd, x, contents);
    460       break;
    461 
    462     default:
    463       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    464 				    contents, rel->r_offset,
    465 				    relocation, rel->r_addend);
    466     }
    467 
    468   return r;
    469 }
    470 
    471 /* Relocate an FR30 ELF section.
    473 
    474    The RELOCATE_SECTION function is called by the new ELF backend linker
    475    to handle the relocations for a section.
    476 
    477    The relocs are always passed as Rela structures; if the section
    478    actually uses Rel structures, the r_addend field will always be
    479    zero.
    480 
    481    This function is responsible for adjusting the section contents as
    482    necessary, and (if using Rela relocs and generating a relocatable
    483    output file) adjusting the reloc addend as necessary.
    484 
    485    This function does not have to worry about setting the reloc
    486    address or the reloc symbol index.
    487 
    488    LOCAL_SYMS is a pointer to the swapped in local symbols.
    489 
    490    LOCAL_SECTIONS is an array giving the section in the input file
    491    corresponding to the st_shndx field of each local symbol.
    492 
    493    The global hash table entry for the global symbols can be found
    494    via elf_sym_hashes (input_bfd).
    495 
    496    When generating relocatable output, this function must handle
    497    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    498    going to be the section symbol corresponding to the output
    499    section, which means that the addend must be adjusted
    500    accordingly.  */
    501 
    502 static bfd_boolean
    503 fr30_elf_relocate_section (bfd *output_bfd,
    504 			   struct bfd_link_info *info,
    505 			   bfd *input_bfd,
    506 			   asection *input_section,
    507 			   bfd_byte *contents,
    508 			   Elf_Internal_Rela *relocs,
    509 			   Elf_Internal_Sym *local_syms,
    510 			   asection **local_sections)
    511 {
    512   Elf_Internal_Shdr *symtab_hdr;
    513   struct elf_link_hash_entry **sym_hashes;
    514   Elf_Internal_Rela *rel;
    515   Elf_Internal_Rela *relend;
    516 
    517   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    518   sym_hashes = elf_sym_hashes (input_bfd);
    519   relend     = relocs + input_section->reloc_count;
    520 
    521   for (rel = relocs; rel < relend; rel ++)
    522     {
    523       reloc_howto_type *howto;
    524       unsigned long r_symndx;
    525       Elf_Internal_Sym *sym;
    526       asection *sec;
    527       struct elf_link_hash_entry *h;
    528       bfd_vma relocation;
    529       bfd_reloc_status_type r;
    530       const char *name;
    531       int r_type;
    532 
    533       r_type = ELF32_R_TYPE (rel->r_info);
    534 
    535       if (   r_type == R_FR30_GNU_VTINHERIT
    536 	  || r_type == R_FR30_GNU_VTENTRY)
    537 	continue;
    538 
    539       r_symndx = ELF32_R_SYM (rel->r_info);
    540 
    541       howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
    542       h      = NULL;
    543       sym    = NULL;
    544       sec    = NULL;
    545 
    546       if (r_symndx < symtab_hdr->sh_info)
    547 	{
    548 	  sym = local_syms + r_symndx;
    549 	  sec = local_sections [r_symndx];
    550 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
    551 
    552 	  name = bfd_elf_string_from_elf_section
    553 	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
    554 	  name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
    555 	}
    556       else
    557 	{
    558 	  bfd_boolean unresolved_reloc, warned, ignored;
    559 
    560 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    561 				   r_symndx, symtab_hdr, sym_hashes,
    562 				   h, sec, relocation,
    563 				   unresolved_reloc, warned, ignored);
    564 
    565 	  name = h->root.root.string;
    566 	}
    567 
    568       if (sec != NULL && discarded_section (sec))
    569 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    570 					 rel, 1, relend, howto, 0, contents);
    571 
    572       if (bfd_link_relocatable (info))
    573 	continue;
    574 
    575       r = fr30_final_link_relocate (howto, input_bfd, input_section,
    576 				     contents, rel, relocation);
    577 
    578       if (r != bfd_reloc_ok)
    579 	{
    580 	  const char * msg = (const char *) NULL;
    581 
    582 	  switch (r)
    583 	    {
    584 	    case bfd_reloc_overflow:
    585 	      (*info->callbacks->reloc_overflow)
    586 		(info, (h ? &h->root : NULL), name, howto->name,
    587 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    588 	      break;
    589 
    590 	    case bfd_reloc_undefined:
    591 	      (*info->callbacks->undefined_symbol)
    592 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
    593 	      break;
    594 
    595 	    case bfd_reloc_outofrange:
    596 	      msg = _("internal error: out of range error");
    597 	      break;
    598 
    599 	    case bfd_reloc_notsupported:
    600 	      msg = _("internal error: unsupported relocation error");
    601 	      break;
    602 
    603 	    case bfd_reloc_dangerous:
    604 	      msg = _("internal error: dangerous relocation");
    605 	      break;
    606 
    607 	    default:
    608 	      msg = _("internal error: unknown error");
    609 	      break;
    610 	    }
    611 
    612 	  if (msg)
    613 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
    614 					 input_section, rel->r_offset);
    615 	}
    616     }
    617 
    618   return TRUE;
    619 }
    620 
    621 /* Return the section that should be marked against GC for a given
    623    relocation.  */
    624 
    625 static asection *
    626 fr30_elf_gc_mark_hook (asection *sec,
    627 		       struct bfd_link_info *info,
    628 		       Elf_Internal_Rela *rel,
    629 		       struct elf_link_hash_entry *h,
    630 		       Elf_Internal_Sym *sym)
    631 {
    632   if (h != NULL)
    633     switch (ELF32_R_TYPE (rel->r_info))
    634       {
    635       case R_FR30_GNU_VTINHERIT:
    636       case R_FR30_GNU_VTENTRY:
    637 	return NULL;
    638       }
    639 
    640   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
    641 }
    642 
    643 /* Look through the relocs for a section during the first phase.
    644    Since we don't do .gots or .plts, we just need to consider the
    645    virtual table relocs for gc.  */
    646 
    647 static bfd_boolean
    648 fr30_elf_check_relocs (bfd *abfd,
    649 		       struct bfd_link_info *info,
    650 		       asection *sec,
    651 		       const Elf_Internal_Rela *relocs)
    652 {
    653   Elf_Internal_Shdr *symtab_hdr;
    654   struct elf_link_hash_entry **sym_hashes;
    655   const Elf_Internal_Rela *rel;
    656   const Elf_Internal_Rela *rel_end;
    657 
    658   if (bfd_link_relocatable (info))
    659     return TRUE;
    660 
    661   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
    662   sym_hashes = elf_sym_hashes (abfd);
    663 
    664   rel_end = relocs + sec->reloc_count;
    665   for (rel = relocs; rel < rel_end; rel++)
    666     {
    667       struct elf_link_hash_entry *h;
    668       unsigned long r_symndx;
    669 
    670       r_symndx = ELF32_R_SYM (rel->r_info);
    671       if (r_symndx < symtab_hdr->sh_info)
    672         h = NULL;
    673       else
    674 	{
    675 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
    676 	  while (h->root.type == bfd_link_hash_indirect
    677 		 || h->root.type == bfd_link_hash_warning)
    678 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    679 
    680 	  /* PR15323, ref flags aren't set for references in the same
    681 	     object.  */
    682 	  h->root.non_ir_ref = 1;
    683 	}
    684 
    685       switch (ELF32_R_TYPE (rel->r_info))
    686         {
    687         /* This relocation describes the C++ object vtable hierarchy.
    688            Reconstruct it for later use during GC.  */
    689         case R_FR30_GNU_VTINHERIT:
    690           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
    691             return FALSE;
    692           break;
    693 
    694         /* This relocation describes which C++ vtable entries are actually
    695            used.  Record for later use during GC.  */
    696         case R_FR30_GNU_VTENTRY:
    697           BFD_ASSERT (h != NULL);
    698           if (h != NULL
    699               && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
    700             return FALSE;
    701           break;
    702         }
    703     }
    704 
    705   return TRUE;
    706 }
    707 
    708 #define ELF_ARCH		bfd_arch_fr30
    710 #define ELF_MACHINE_CODE	EM_FR30
    711 #define ELF_MACHINE_ALT1	EM_CYGNUS_FR30
    712 #define ELF_MAXPAGESIZE		0x1000
    713 
    714 #define TARGET_BIG_SYM          fr30_elf32_vec
    715 #define TARGET_BIG_NAME		"elf32-fr30"
    716 
    717 #define elf_info_to_howto_rel			NULL
    718 #define elf_info_to_howto			fr30_info_to_howto_rela
    719 #define elf_backend_relocate_section		fr30_elf_relocate_section
    720 #define elf_backend_gc_mark_hook		fr30_elf_gc_mark_hook
    721 #define elf_backend_check_relocs                fr30_elf_check_relocs
    722 
    723 #define elf_backend_can_gc_sections		1
    724 #define elf_backend_rela_normal			1
    725 
    726 #define bfd_elf32_bfd_reloc_type_lookup		fr30_reloc_type_lookup
    727 #define bfd_elf32_bfd_reloc_name_lookup	fr30_reloc_name_lookup
    728 
    729 #include "elf32-target.h"
    730