(root)/
binutils-2.41/
bfd/
elf32-fr30.c
       1  /* FR30-specific support for 32-bit ELF.
       2     Copyright (C) 1998-2023 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  	 0,			/* size */
      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  	 2,			/* size */
      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  	 4,			/* size */
      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  	 4,			/* size */
      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  	 4,			/* size */
     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  	 2,			/* size */
     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  	 2,			/* size */
     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  	 2,			/* size */
     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  	 2,			/* size */
     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  	 2,			/* size */
     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  	 2,			/* size */
     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  	 4,			/* size */
     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  	 4,			/* size */
     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.  */
     233  
     234  static bfd_reloc_status_type
     235  fr30_elf_i20_reloc (bfd *abfd,
     236  		    arelent *reloc_entry,
     237  		    asymbol *symbol,
     238  		    void * data,
     239  		    asection *input_section,
     240  		    bfd *output_bfd,
     241  		    char **error_message ATTRIBUTE_UNUSED)
     242  {
     243    bfd_vma relocation;
     244    unsigned long x;
     245  
     246    /* This part is from bfd_elf_generic_reloc.  */
     247    if (output_bfd != (bfd *) NULL
     248        && (symbol->flags & BSF_SECTION_SYM) == 0
     249        && (! reloc_entry->howto->partial_inplace
     250  	  || reloc_entry->addend == 0))
     251      {
     252        reloc_entry->address += input_section->output_offset;
     253        return bfd_reloc_ok;
     254      }
     255  
     256    if (output_bfd != NULL)
     257      /* FIXME: See bfd_perform_relocation.  Is this right?  */
     258      return bfd_reloc_ok;
     259  
     260    relocation =
     261      symbol->value
     262      + symbol->section->output_section->vma
     263      + symbol->section->output_offset
     264      + reloc_entry->addend;
     265  
     266    if (relocation > (((bfd_vma) 1 << 20) - 1))
     267      return bfd_reloc_overflow;
     268  
     269    x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
     270    x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
     271    bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
     272  
     273    return bfd_reloc_ok;
     274  }
     275  
     276  /* Utility to actually perform a R_FR30_48 reloc.  */
     277  
     278  static bfd_reloc_status_type
     279  fr30_elf_i32_reloc (bfd *abfd,
     280  		    arelent *reloc_entry,
     281  		    asymbol *symbol,
     282  		    void * data,
     283  		    asection *input_section,
     284  		    bfd *output_bfd,
     285  		    char **error_message ATTRIBUTE_UNUSED)
     286  {
     287    bfd_vma relocation;
     288  
     289    /* This part is from bfd_elf_generic_reloc.  */
     290    if (output_bfd != (bfd *) NULL
     291        && (symbol->flags & BSF_SECTION_SYM) == 0
     292        && (! reloc_entry->howto->partial_inplace
     293  	  || reloc_entry->addend == 0))
     294      {
     295        reloc_entry->address += input_section->output_offset;
     296        return bfd_reloc_ok;
     297      }
     298  
     299    if (output_bfd != NULL)
     300      /* FIXME: See bfd_perform_relocation.  Is this right?  */
     301      return bfd_reloc_ok;
     302  
     303    relocation =
     304      symbol->value
     305      + symbol->section->output_section->vma
     306      + symbol->section->output_offset
     307      + reloc_entry->addend;
     308  
     309    bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
     310  
     311    return bfd_reloc_ok;
     312  }
     313  
     314  /* Map BFD reloc types to FR30 ELF reloc types.  */
     315  
     316  struct fr30_reloc_map
     317  {
     318    bfd_reloc_code_real_type bfd_reloc_val;
     319    unsigned int fr30_reloc_val;
     320  };
     321  
     322  static const struct fr30_reloc_map fr30_reloc_map [] =
     323  {
     324    { BFD_RELOC_NONE,	      R_FR30_NONE },
     325    { BFD_RELOC_8,	      R_FR30_8 },
     326    { BFD_RELOC_FR30_20,	      R_FR30_20 },
     327    { BFD_RELOC_32,	      R_FR30_32 },
     328    { BFD_RELOC_FR30_48,	      R_FR30_48 },
     329    { BFD_RELOC_FR30_6_IN_4,    R_FR30_6_IN_4 },
     330    { BFD_RELOC_FR30_8_IN_8,    R_FR30_8_IN_8 },
     331    { BFD_RELOC_FR30_9_IN_8,    R_FR30_9_IN_8 },
     332    { BFD_RELOC_FR30_10_IN_8,   R_FR30_10_IN_8 },
     333    { BFD_RELOC_FR30_9_PCREL,   R_FR30_9_PCREL },
     334    { BFD_RELOC_FR30_12_PCREL,  R_FR30_12_PCREL },
     335    { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
     336    { BFD_RELOC_VTABLE_ENTRY,   R_FR30_GNU_VTENTRY },
     337  };
     338  
     339  static reloc_howto_type *
     340  fr30_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     341  			bfd_reloc_code_real_type code)
     342  {
     343    unsigned int i;
     344  
     345    for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
     346         i--;)
     347      if (fr30_reloc_map [i].bfd_reloc_val == code)
     348        return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
     349  
     350    return NULL;
     351  }
     352  
     353  static reloc_howto_type *
     354  fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
     355  {
     356    unsigned int i;
     357  
     358    for (i = 0;
     359         i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
     360         i++)
     361      if (fr30_elf_howto_table[i].name != NULL
     362  	&& strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
     363        return &fr30_elf_howto_table[i];
     364  
     365    return NULL;
     366  }
     367  
     368  /* Set the howto pointer for an FR30 ELF reloc.  */
     369  
     370  static bool
     371  fr30_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
     372  			 arelent *cache_ptr,
     373  			 Elf_Internal_Rela *dst)
     374  {
     375    unsigned int r_type;
     376  
     377    r_type = ELF32_R_TYPE (dst->r_info);
     378    if (r_type >= (unsigned int) R_FR30_max)
     379      {
     380        /* xgettext:c-format */
     381        _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
     382  			  abfd, r_type);
     383        bfd_set_error (bfd_error_bad_value);
     384        return false;
     385      }
     386    cache_ptr->howto = & fr30_elf_howto_table [r_type];
     387    return true;
     388  }
     389  
     390  /* Perform a single relocation.  By default we use the standard BFD
     391     routines, but a few relocs, we have to do them ourselves.  */
     392  
     393  static bfd_reloc_status_type
     394  fr30_final_link_relocate (reloc_howto_type *howto,
     395  			  bfd *input_bfd,
     396  			  asection *input_section,
     397  			  bfd_byte *contents,
     398  			  Elf_Internal_Rela *rel,
     399  			  bfd_vma relocation)
     400  {
     401    bfd_reloc_status_type r = bfd_reloc_ok;
     402    bfd_vma x;
     403    bfd_signed_vma srel;
     404  
     405    switch (howto->type)
     406      {
     407      case R_FR30_20:
     408        contents   += rel->r_offset;
     409        relocation += rel->r_addend;
     410  
     411        if (relocation > ((1 << 20) - 1))
     412  	return bfd_reloc_overflow;
     413  
     414        x = bfd_get_32 (input_bfd, contents);
     415        x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
     416        bfd_put_32 (input_bfd, x, contents);
     417        break;
     418  
     419      case R_FR30_48:
     420        contents   += rel->r_offset + 2;
     421        relocation += rel->r_addend;
     422        bfd_put_32 (input_bfd, relocation, contents);
     423        break;
     424  
     425      case R_FR30_9_PCREL:
     426        contents   += rel->r_offset + 1;
     427        srel = (bfd_signed_vma) relocation;
     428        srel += rel->r_addend;
     429        srel -= rel->r_offset;
     430        srel -= 2;  /* Branch instructions add 2 to the PC...  */
     431        srel -= (input_section->output_section->vma +
     432  		     input_section->output_offset);
     433  
     434        if (srel & 1)
     435  	return bfd_reloc_outofrange;
     436        if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
     437  	return bfd_reloc_overflow;
     438  
     439        bfd_put_8 (input_bfd, srel >> 1, contents);
     440        break;
     441  
     442      case R_FR30_12_PCREL:
     443        contents   += rel->r_offset;
     444        srel = (bfd_signed_vma) relocation;
     445        srel += rel->r_addend;
     446        srel -= rel->r_offset;
     447        srel -= 2; /* Branch instructions add 2 to the PC...  */
     448        srel -= (input_section->output_section->vma +
     449  		     input_section->output_offset);
     450  
     451        if (srel & 1)
     452  	return bfd_reloc_outofrange;
     453        if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
     454  	  return bfd_reloc_overflow;
     455  
     456        x = bfd_get_16 (input_bfd, contents);
     457        x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
     458        bfd_put_16 (input_bfd, x, contents);
     459        break;
     460  
     461      default:
     462        r = _bfd_final_link_relocate (howto, input_bfd, input_section,
     463  				    contents, rel->r_offset,
     464  				    relocation, rel->r_addend);
     465      }
     466  
     467    return r;
     468  }
     469  
     470  /* Relocate an FR30 ELF section.
     471  
     472     The RELOCATE_SECTION function is called by the new ELF backend linker
     473     to handle the relocations for a section.
     474  
     475     The relocs are always passed as Rela structures; if the section
     476     actually uses Rel structures, the r_addend field will always be
     477     zero.
     478  
     479     This function is responsible for adjusting the section contents as
     480     necessary, and (if using Rela relocs and generating a relocatable
     481     output file) adjusting the reloc addend as necessary.
     482  
     483     This function does not have to worry about setting the reloc
     484     address or the reloc symbol index.
     485  
     486     LOCAL_SYMS is a pointer to the swapped in local symbols.
     487  
     488     LOCAL_SECTIONS is an array giving the section in the input file
     489     corresponding to the st_shndx field of each local symbol.
     490  
     491     The global hash table entry for the global symbols can be found
     492     via elf_sym_hashes (input_bfd).
     493  
     494     When generating relocatable output, this function must handle
     495     STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
     496     going to be the section symbol corresponding to the output
     497     section, which means that the addend must be adjusted
     498     accordingly.  */
     499  
     500  static int
     501  fr30_elf_relocate_section (bfd *output_bfd,
     502  			   struct bfd_link_info *info,
     503  			   bfd *input_bfd,
     504  			   asection *input_section,
     505  			   bfd_byte *contents,
     506  			   Elf_Internal_Rela *relocs,
     507  			   Elf_Internal_Sym *local_syms,
     508  			   asection **local_sections)
     509  {
     510    Elf_Internal_Shdr *symtab_hdr;
     511    struct elf_link_hash_entry **sym_hashes;
     512    Elf_Internal_Rela *rel;
     513    Elf_Internal_Rela *relend;
     514  
     515    symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
     516    sym_hashes = elf_sym_hashes (input_bfd);
     517    relend     = relocs + input_section->reloc_count;
     518  
     519    for (rel = relocs; rel < relend; rel ++)
     520      {
     521        reloc_howto_type *howto;
     522        unsigned long r_symndx;
     523        Elf_Internal_Sym *sym;
     524        asection *sec;
     525        struct elf_link_hash_entry *h;
     526        bfd_vma relocation;
     527        bfd_reloc_status_type r;
     528        const char *name;
     529        int r_type;
     530  
     531        r_type = ELF32_R_TYPE (rel->r_info);
     532  
     533        if (   r_type == R_FR30_GNU_VTINHERIT
     534  	  || r_type == R_FR30_GNU_VTENTRY)
     535  	continue;
     536  
     537        r_symndx = ELF32_R_SYM (rel->r_info);
     538  
     539        howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
     540        h      = NULL;
     541        sym    = NULL;
     542        sec    = NULL;
     543  
     544        if (r_symndx < symtab_hdr->sh_info)
     545  	{
     546  	  sym = local_syms + r_symndx;
     547  	  sec = local_sections [r_symndx];
     548  	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
     549  
     550  	  name = bfd_elf_string_from_elf_section
     551  	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
     552  	  name = name == NULL ? bfd_section_name (sec) : name;
     553  	}
     554        else
     555  	{
     556  	  bool unresolved_reloc, warned, ignored;
     557  
     558  	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
     559  				   r_symndx, symtab_hdr, sym_hashes,
     560  				   h, sec, relocation,
     561  				   unresolved_reloc, warned, ignored);
     562  
     563  	  name = h->root.root.string;
     564  	}
     565  
     566        if (sec != NULL && discarded_section (sec))
     567  	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
     568  					 rel, 1, relend, howto, 0, contents);
     569  
     570        if (bfd_link_relocatable (info))
     571  	continue;
     572  
     573        r = fr30_final_link_relocate (howto, input_bfd, input_section,
     574  				     contents, rel, relocation);
     575  
     576        if (r != bfd_reloc_ok)
     577  	{
     578  	  const char * msg = (const char *) NULL;
     579  
     580  	  switch (r)
     581  	    {
     582  	    case bfd_reloc_overflow:
     583  	      (*info->callbacks->reloc_overflow)
     584  		(info, (h ? &h->root : NULL), name, howto->name,
     585  		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
     586  	      break;
     587  
     588  	    case bfd_reloc_undefined:
     589  	      (*info->callbacks->undefined_symbol)
     590  		(info, name, input_bfd, input_section, rel->r_offset, true);
     591  	      break;
     592  
     593  	    case bfd_reloc_outofrange:
     594  	      msg = _("internal error: out of range error");
     595  	      break;
     596  
     597  	    case bfd_reloc_notsupported:
     598  	      msg = _("internal error: unsupported relocation error");
     599  	      break;
     600  
     601  	    case bfd_reloc_dangerous:
     602  	      msg = _("internal error: dangerous relocation");
     603  	      break;
     604  
     605  	    default:
     606  	      msg = _("internal error: unknown error");
     607  	      break;
     608  	    }
     609  
     610  	  if (msg)
     611  	    (*info->callbacks->warning) (info, msg, name, input_bfd,
     612  					 input_section, rel->r_offset);
     613  	}
     614      }
     615  
     616    return true;
     617  }
     618  
     619  /* Return the section that should be marked against GC for a given
     620     relocation.  */
     621  
     622  static asection *
     623  fr30_elf_gc_mark_hook (asection *sec,
     624  		       struct bfd_link_info *info,
     625  		       Elf_Internal_Rela *rel,
     626  		       struct elf_link_hash_entry *h,
     627  		       Elf_Internal_Sym *sym)
     628  {
     629    if (h != NULL)
     630      switch (ELF32_R_TYPE (rel->r_info))
     631        {
     632        case R_FR30_GNU_VTINHERIT:
     633        case R_FR30_GNU_VTENTRY:
     634  	return NULL;
     635        }
     636  
     637    return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
     638  }
     639  
     640  /* Look through the relocs for a section during the first phase.
     641     Since we don't do .gots or .plts, we just need to consider the
     642     virtual table relocs for gc.  */
     643  
     644  static bool
     645  fr30_elf_check_relocs (bfd *abfd,
     646  		       struct bfd_link_info *info,
     647  		       asection *sec,
     648  		       const Elf_Internal_Rela *relocs)
     649  {
     650    Elf_Internal_Shdr *symtab_hdr;
     651    struct elf_link_hash_entry **sym_hashes;
     652    const Elf_Internal_Rela *rel;
     653    const Elf_Internal_Rela *rel_end;
     654  
     655    if (bfd_link_relocatable (info))
     656      return true;
     657  
     658    symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
     659    sym_hashes = elf_sym_hashes (abfd);
     660  
     661    rel_end = relocs + sec->reloc_count;
     662    for (rel = relocs; rel < rel_end; rel++)
     663      {
     664        struct elf_link_hash_entry *h;
     665        unsigned long r_symndx;
     666  
     667        r_symndx = ELF32_R_SYM (rel->r_info);
     668        if (r_symndx < symtab_hdr->sh_info)
     669  	h = NULL;
     670        else
     671  	{
     672  	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
     673  	  while (h->root.type == bfd_link_hash_indirect
     674  		 || h->root.type == bfd_link_hash_warning)
     675  	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
     676  	}
     677  
     678        switch (ELF32_R_TYPE (rel->r_info))
     679  	{
     680  	/* This relocation describes the C++ object vtable hierarchy.
     681  	   Reconstruct it for later use during GC.  */
     682  	case R_FR30_GNU_VTINHERIT:
     683  	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
     684  	    return false;
     685  	  break;
     686  
     687  	/* This relocation describes which C++ vtable entries are actually
     688  	   used.  Record for later use during GC.  */
     689  	case R_FR30_GNU_VTENTRY:
     690  	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
     691  	    return false;
     692  	  break;
     693  	}
     694      }
     695  
     696    return true;
     697  }
     698  
     699  #define ELF_ARCH		bfd_arch_fr30
     700  #define ELF_MACHINE_CODE	EM_FR30
     701  #define ELF_MACHINE_ALT1	EM_CYGNUS_FR30
     702  #define ELF_MAXPAGESIZE		0x1000
     703  
     704  #define TARGET_BIG_SYM		fr30_elf32_vec
     705  #define TARGET_BIG_NAME		"elf32-fr30"
     706  
     707  #define elf_info_to_howto_rel			NULL
     708  #define elf_info_to_howto			fr30_info_to_howto_rela
     709  #define elf_backend_relocate_section		fr30_elf_relocate_section
     710  #define elf_backend_gc_mark_hook		fr30_elf_gc_mark_hook
     711  #define elf_backend_check_relocs		fr30_elf_check_relocs
     712  
     713  #define elf_backend_can_gc_sections		1
     714  #define elf_backend_rela_normal			1
     715  
     716  #define bfd_elf32_bfd_reloc_type_lookup		fr30_reloc_type_lookup
     717  #define bfd_elf32_bfd_reloc_name_lookup		fr30_reloc_name_lookup
     718  
     719  #include "elf32-target.h"