Home | History | Annotate | Line # | Download | only in bfd
elf32-fr30.c revision 1.9
      1 /* FR30-specific support for 32-bit ELF.
      2    Copyright (C) 1998-2020 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 bfd_boolean
    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 (_("%pB: unsupported relocation type %#x"),
    385 			  abfd, r_type);
    386       bfd_set_error (bfd_error_bad_value);
    387       return FALSE;
    388     }
    389   cache_ptr->howto = & fr30_elf_howto_table [r_type];
    390   return TRUE;
    391 }
    392 
    393 /* Perform a single relocation.  By default we use the standard BFD
    395    routines, but a few relocs, we have to do them ourselves.  */
    396 
    397 static bfd_reloc_status_type
    398 fr30_final_link_relocate (reloc_howto_type *howto,
    399 			  bfd *input_bfd,
    400 			  asection *input_section,
    401 			  bfd_byte *contents,
    402 			  Elf_Internal_Rela *rel,
    403 			  bfd_vma relocation)
    404 {
    405   bfd_reloc_status_type r = bfd_reloc_ok;
    406   bfd_vma x;
    407   bfd_signed_vma srel;
    408 
    409   switch (howto->type)
    410     {
    411     case R_FR30_20:
    412       contents   += rel->r_offset;
    413       relocation += rel->r_addend;
    414 
    415       if (relocation > ((1 << 20) - 1))
    416 	return bfd_reloc_overflow;
    417 
    418       x = bfd_get_32 (input_bfd, contents);
    419       x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
    420       bfd_put_32 (input_bfd, x, contents);
    421       break;
    422 
    423     case R_FR30_48:
    424       contents   += rel->r_offset + 2;
    425       relocation += rel->r_addend;
    426       bfd_put_32 (input_bfd, relocation, contents);
    427       break;
    428 
    429     case R_FR30_9_PCREL:
    430       contents   += rel->r_offset + 1;
    431       srel = (bfd_signed_vma) relocation;
    432       srel += rel->r_addend;
    433       srel -= rel->r_offset;
    434       srel -= 2;  /* Branch instructions add 2 to the PC...  */
    435       srel -= (input_section->output_section->vma +
    436 		     input_section->output_offset);
    437 
    438       if (srel & 1)
    439 	return bfd_reloc_outofrange;
    440       if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
    441 	return bfd_reloc_overflow;
    442 
    443       bfd_put_8 (input_bfd, srel >> 1, contents);
    444       break;
    445 
    446     case R_FR30_12_PCREL:
    447       contents   += rel->r_offset;
    448       srel = (bfd_signed_vma) relocation;
    449       srel += rel->r_addend;
    450       srel -= rel->r_offset;
    451       srel -= 2; /* Branch instructions add 2 to the PC...  */
    452       srel -= (input_section->output_section->vma +
    453 		     input_section->output_offset);
    454 
    455       if (srel & 1)
    456 	return bfd_reloc_outofrange;
    457       if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
    458 	  return bfd_reloc_overflow;
    459 
    460       x = bfd_get_16 (input_bfd, contents);
    461       x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
    462       bfd_put_16 (input_bfd, x, contents);
    463       break;
    464 
    465     default:
    466       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    467 				    contents, rel->r_offset,
    468 				    relocation, rel->r_addend);
    469     }
    470 
    471   return r;
    472 }
    473 
    474 /* Relocate an FR30 ELF section.
    476 
    477    The RELOCATE_SECTION function is called by the new ELF backend linker
    478    to handle the relocations for a section.
    479 
    480    The relocs are always passed as Rela structures; if the section
    481    actually uses Rel structures, the r_addend field will always be
    482    zero.
    483 
    484    This function is responsible for adjusting the section contents as
    485    necessary, and (if using Rela relocs and generating a relocatable
    486    output file) adjusting the reloc addend as necessary.
    487 
    488    This function does not have to worry about setting the reloc
    489    address or the reloc symbol index.
    490 
    491    LOCAL_SYMS is a pointer to the swapped in local symbols.
    492 
    493    LOCAL_SECTIONS is an array giving the section in the input file
    494    corresponding to the st_shndx field of each local symbol.
    495 
    496    The global hash table entry for the global symbols can be found
    497    via elf_sym_hashes (input_bfd).
    498 
    499    When generating relocatable output, this function must handle
    500    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    501    going to be the section symbol corresponding to the output
    502    section, which means that the addend must be adjusted
    503    accordingly.  */
    504 
    505 static bfd_boolean
    506 fr30_elf_relocate_section (bfd *output_bfd,
    507 			   struct bfd_link_info *info,
    508 			   bfd *input_bfd,
    509 			   asection *input_section,
    510 			   bfd_byte *contents,
    511 			   Elf_Internal_Rela *relocs,
    512 			   Elf_Internal_Sym *local_syms,
    513 			   asection **local_sections)
    514 {
    515   Elf_Internal_Shdr *symtab_hdr;
    516   struct elf_link_hash_entry **sym_hashes;
    517   Elf_Internal_Rela *rel;
    518   Elf_Internal_Rela *relend;
    519 
    520   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    521   sym_hashes = elf_sym_hashes (input_bfd);
    522   relend     = relocs + input_section->reloc_count;
    523 
    524   for (rel = relocs; rel < relend; rel ++)
    525     {
    526       reloc_howto_type *howto;
    527       unsigned long r_symndx;
    528       Elf_Internal_Sym *sym;
    529       asection *sec;
    530       struct elf_link_hash_entry *h;
    531       bfd_vma relocation;
    532       bfd_reloc_status_type r;
    533       const char *name;
    534       int r_type;
    535 
    536       r_type = ELF32_R_TYPE (rel->r_info);
    537 
    538       if (   r_type == R_FR30_GNU_VTINHERIT
    539 	  || r_type == R_FR30_GNU_VTENTRY)
    540 	continue;
    541 
    542       r_symndx = ELF32_R_SYM (rel->r_info);
    543 
    544       howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
    545       h      = NULL;
    546       sym    = NULL;
    547       sec    = NULL;
    548 
    549       if (r_symndx < symtab_hdr->sh_info)
    550 	{
    551 	  sym = local_syms + r_symndx;
    552 	  sec = local_sections [r_symndx];
    553 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
    554 
    555 	  name = bfd_elf_string_from_elf_section
    556 	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
    557 	  name = name == NULL ? bfd_section_name (sec) : name;
    558 	}
    559       else
    560 	{
    561 	  bfd_boolean unresolved_reloc, warned, ignored;
    562 
    563 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    564 				   r_symndx, symtab_hdr, sym_hashes,
    565 				   h, sec, relocation,
    566 				   unresolved_reloc, warned, ignored);
    567 
    568 	  name = h->root.root.string;
    569 	}
    570 
    571       if (sec != NULL && discarded_section (sec))
    572 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    573 					 rel, 1, relend, howto, 0, contents);
    574 
    575       if (bfd_link_relocatable (info))
    576 	continue;
    577 
    578       r = fr30_final_link_relocate (howto, input_bfd, input_section,
    579 				     contents, rel, relocation);
    580 
    581       if (r != bfd_reloc_ok)
    582 	{
    583 	  const char * msg = (const char *) NULL;
    584 
    585 	  switch (r)
    586 	    {
    587 	    case bfd_reloc_overflow:
    588 	      (*info->callbacks->reloc_overflow)
    589 		(info, (h ? &h->root : NULL), name, howto->name,
    590 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    591 	      break;
    592 
    593 	    case bfd_reloc_undefined:
    594 	      (*info->callbacks->undefined_symbol)
    595 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
    596 	      break;
    597 
    598 	    case bfd_reloc_outofrange:
    599 	      msg = _("internal error: out of range error");
    600 	      break;
    601 
    602 	    case bfd_reloc_notsupported:
    603 	      msg = _("internal error: unsupported relocation error");
    604 	      break;
    605 
    606 	    case bfd_reloc_dangerous:
    607 	      msg = _("internal error: dangerous relocation");
    608 	      break;
    609 
    610 	    default:
    611 	      msg = _("internal error: unknown error");
    612 	      break;
    613 	    }
    614 
    615 	  if (msg)
    616 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
    617 					 input_section, rel->r_offset);
    618 	}
    619     }
    620 
    621   return TRUE;
    622 }
    623 
    624 /* Return the section that should be marked against GC for a given
    626    relocation.  */
    627 
    628 static asection *
    629 fr30_elf_gc_mark_hook (asection *sec,
    630 		       struct bfd_link_info *info,
    631 		       Elf_Internal_Rela *rel,
    632 		       struct elf_link_hash_entry *h,
    633 		       Elf_Internal_Sym *sym)
    634 {
    635   if (h != NULL)
    636     switch (ELF32_R_TYPE (rel->r_info))
    637       {
    638       case R_FR30_GNU_VTINHERIT:
    639       case R_FR30_GNU_VTENTRY:
    640 	return NULL;
    641       }
    642 
    643   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
    644 }
    645 
    646 /* Look through the relocs for a section during the first phase.
    647    Since we don't do .gots or .plts, we just need to consider the
    648    virtual table relocs for gc.  */
    649 
    650 static bfd_boolean
    651 fr30_elf_check_relocs (bfd *abfd,
    652 		       struct bfd_link_info *info,
    653 		       asection *sec,
    654 		       const Elf_Internal_Rela *relocs)
    655 {
    656   Elf_Internal_Shdr *symtab_hdr;
    657   struct elf_link_hash_entry **sym_hashes;
    658   const Elf_Internal_Rela *rel;
    659   const Elf_Internal_Rela *rel_end;
    660 
    661   if (bfd_link_relocatable (info))
    662     return TRUE;
    663 
    664   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
    665   sym_hashes = elf_sym_hashes (abfd);
    666 
    667   rel_end = relocs + sec->reloc_count;
    668   for (rel = relocs; rel < rel_end; rel++)
    669     {
    670       struct elf_link_hash_entry *h;
    671       unsigned long r_symndx;
    672 
    673       r_symndx = ELF32_R_SYM (rel->r_info);
    674       if (r_symndx < symtab_hdr->sh_info)
    675 	h = NULL;
    676       else
    677 	{
    678 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
    679 	  while (h->root.type == bfd_link_hash_indirect
    680 		 || h->root.type == bfd_link_hash_warning)
    681 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    682 	}
    683 
    684       switch (ELF32_R_TYPE (rel->r_info))
    685 	{
    686 	/* This relocation describes the C++ object vtable hierarchy.
    687 	   Reconstruct it for later use during GC.  */
    688 	case R_FR30_GNU_VTINHERIT:
    689 	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
    690 	    return FALSE;
    691 	  break;
    692 
    693 	/* This relocation describes which C++ vtable entries are actually
    694 	   used.  Record for later use during GC.  */
    695 	case R_FR30_GNU_VTENTRY:
    696 	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
    697 	    return FALSE;
    698 	  break;
    699 	}
    700     }
    701 
    702   return TRUE;
    703 }
    704 
    705 #define ELF_ARCH		bfd_arch_fr30
    707 #define ELF_MACHINE_CODE	EM_FR30
    708 #define ELF_MACHINE_ALT1	EM_CYGNUS_FR30
    709 #define ELF_MAXPAGESIZE		0x1000
    710 
    711 #define TARGET_BIG_SYM		fr30_elf32_vec
    712 #define TARGET_BIG_NAME		"elf32-fr30"
    713 
    714 #define elf_info_to_howto_rel			NULL
    715 #define elf_info_to_howto			fr30_info_to_howto_rela
    716 #define elf_backend_relocate_section		fr30_elf_relocate_section
    717 #define elf_backend_gc_mark_hook		fr30_elf_gc_mark_hook
    718 #define elf_backend_check_relocs		fr30_elf_check_relocs
    719 
    720 #define elf_backend_can_gc_sections		1
    721 #define elf_backend_rela_normal			1
    722 
    723 #define bfd_elf32_bfd_reloc_type_lookup		fr30_reloc_type_lookup
    724 #define bfd_elf32_bfd_reloc_name_lookup		fr30_reloc_name_lookup
    725 
    726 #include "elf32-target.h"
    727